/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "物体节点.h"

#include <mutex>
#include <物体/物体.h>
#include <几何计算.h>
#include <core/动画/an_曲线.h>
#include <场景/intern/S_Scene.h>
#include <物体/S_摄像机.h>
//#include <矢量计算.h>


#include <Context/当前默认操作数据.h>
#include <Context/节点数据操作.h>
#include "Context/数据创建销毁.h"
#include "Context/虚拟体物体构建.h"
#include "节点编辑.h"
#include "物体编辑/编辑骨骼.h"

#include "节点/插座/list/list物体插座.h"
#include "节点/插座/list/list数值插座.h"
#include "节点/插座/通用插座.h"
#include "节点/插座/材质纹理插座.h"
#include "节点/插座/字符插座.h"
#include "节点/socket_utils.h"

#include "异步解算/物理异步解算.h"


#include "物体类JIT函数.h"






static S_物体* f_创建骨骼物体(S_设备环境& ctx, bool 拾取) {
	S_物体* 根骨骼;
	根骨骼 = f_ob_创建骨骼(nullptr, ctx);
	根骨骼->m_Name = u"根骨骼";
	f_node_create骨骼虚拟体网格(根骨骼, false);
	f_ob_getMesh(根骨骼, 0)->m_拾取 = 拾取;
	return 根骨骼;
}

static S_物体* f_递归构建骨骼网格体(S_物体* 物体, S_设备环境& ctx) {
	S_物体* ob = nullptr;

	if (物体->m_Type == E_物体类型::t_骨骼) {
		f_node_将现有物体包装成骨骼网格(ctx, 物体, nullptr);
		return 物体;
	}

	for (auto& e : 物体->m_子物体) {
		ob = f_递归构建骨骼网格体(static_cast<S_物体*>(e), ctx);
		if (ob) return ob;
	}

	return nullptr;
}




static void f_骨骼物体构建骨节物体(S_物体* 骨节, const S_物体* 骨骼) {
	for (auto& e : 骨骼->m_子物体) {
		S_物体* 骨节物体 = ((S_物体*)(e->m_UserData));

		骨节物体->m_实例ID = static_cast<S_物体*>(e)->m_实例ID + 1;
		骨节物体->m_UserData = (void*)e;
		f_ob_add子物体(骨节, 骨节物体);

		if (e->m_子物体.size()) {
			f_骨骼物体构建骨节物体(骨节, static_cast<S_物体*>(e));
		}
	}
}

static S_物体* f_递归更新骨节(S_物体* 骨骼, uint32& depth) {
	S_物体* ob = nullptr;

	if (骨骼->m_Type == E_物体类型::t_骨骼) {
		骨骼->m_实例ID = depth;
		++depth;

		
		uint32 num = 骨骼->m_子物体.size();
		if (num) {
			for (uint32 i = 0; i < num; ++i) {
				ob = f_递归更新骨节(static_cast<S_物体*>(骨骼->m_子物体[i]), depth);
			}
		}
	}

	return nullptr;
}

static void f_递归设置骨骼网格深度绘制(S_物体* 物体, float32 深度) {
	S_物体* ob = nullptr;

	if (物体->m_Type == E_物体类型::t_骨骼) {
		f_mesh_get网格元素绘制属性(f_ob_getMesh(物体, 0)).m_DepthScale = 深度;
		f_mesh_get网格元素绘制属性(f_ob_getMesh(物体, 1)).m_DepthScale = 深度;
		if (物体->m_DataNum > 2) {
			f_mesh_get网格元素绘制属性(f_ob_getMesh(物体, 2)).m_DepthScale = 深度;
			f_mesh_get网格元素绘制属性(f_ob_getMesh(物体, 3)).m_DepthScale = 深度;
		}
	}

	for (auto& e : 物体->m_子物体) {
		f_递归设置骨骼网格深度绘制(static_cast<S_物体*>(e), 深度);
	}
}




static void f_从骨节更新编辑骨骼(S_物体* 根骨骼, S_物体** 骨干, S_物体** 骨节, uint32 depth, float32* 骨骼长度, const vec4& 父骨骼旋转, const float32 父骨骼长度) {
	uint32 num = 根骨骼->m_子物体.size();
	float32 最大长度 = 0.1;
	float32 骨节大小 = 0.1;


	S_骨骼* 骨骼 = f_ob_from骨骼(根骨骼);
	
	
	for (uint32 i = 0; i < num; ++i) {
		S_物体* 末端骨骼 = static_cast<S_物体*>(根骨骼->m_子物体[i]);

		S_骨骼* 骨骼数据 = f_ob_from骨骼(末端骨骼);

		vec3 e = 末端骨骼->m_变换.position + DEF_骨骼朝向;
		float32 两骨节距离 = 0;


		vec4 newQuat = 父骨骼旋转;
		if (depth) {
			vec3 s = 根骨骼->m_变换.position;
			vec3 骨骼方向 = e - s;


			两骨节距离 = vec_normalize(&骨骼方向);
			骨骼长度[末端骨骼->m_实例ID] = 两骨节距离;

			最大长度 = DEF_Max(根骨骼->m_变换.scale.x, 两骨节距离);
			最大长度 = 两骨节距离;
			骨骼数据->m_长度 = 两骨节距离;


			骨骼方向 = f_graph_quat变换坐标(f_graph_quat反向(父骨骼旋转), 骨骼方向);
			vec4 q = f_graph_quat两向量(骨骼方向, DEF_骨骼朝向);
			vec3 rot = f_graph_四元数转欧拉角(q);

			rot = vec3{ -rot.x, -rot.y, rot.z };
			骨干[末端骨骼->m_实例ID]->f_set旋转(rot, 0);

			骨干[末端骨骼->m_实例ID]->f_set位置(s, 0);
			骨干[末端骨骼->m_实例ID]->f_set缩放({ 1, 1 ,1 }, 0);


			骨节大小 = DEF_Min(vec_len(骨骼方向), 骨节大小);


			vec4 newQuat = f_graph_quatNormalize(f_graph_quat相乘(q, 父骨骼旋转));
		}
		else {
			骨干[末端骨骼->m_实例ID]->m_变换.position = 末端骨骼->m_变换.position + DEF_骨骼朝向;
			骨节[末端骨骼->m_实例ID]->m_变换.position = 末端骨骼->m_变换.position + DEF_骨骼朝向;
		}
		

		f_从骨节更新编辑骨骼(末端骨骼, 骨干, 骨节, depth + 1, 骨骼长度, newQuat, 两骨节距离);
	}

	
	骨节[根骨骼->m_实例ID]->f_set缩放(vec3{ 骨节大小, 骨节大小, 骨节大小 }, 0);
	if (depth) {
		
	}
	else {
		//骨节[根骨骼->m_实例ID]->f_set缩放(vec3{ 骨节大小, 骨节大小, 骨节大小 }, 0);
	}

}


static void f_将超出长度范围的骨节移动到范围内(S_物体* 根骨骼, S_物体** 骨节, uint32 depth, const float32* 骨骼长度, const vec3 移动修正) {
	uint32 num = 根骨骼->m_子物体.size();
	for (uint32 i = 0; i < num; ++i) {
		S_物体* 骨骼 = static_cast<S_物体*>(根骨骼->m_子物体[i]);
		S_物体* 当前开始骨节;

		vec3 e = f_从骨头取末端骨节(骨骼)->m_变换.position;
		if (depth) {
			当前开始骨节 = f_从骨头取前端骨节(骨骼);
		}
		else {
			当前开始骨节 = 骨节[0];
		}
		vec3 s = 当前开始骨节->m_变换.position;
		vec3 骨骼方向 = e - s;
		float32 两骨节距离 = vec_normalize(&骨骼方向);

		if (两骨节距离 > 骨骼长度[骨骼->m_实例ID] || 两骨节距离 < 骨骼长度[骨骼->m_实例ID]) {
			vec_mul(&骨骼方向, 两骨节距离 - 骨骼长度[骨骼->m_实例ID]);
			vec_sub(&(f_从骨头取末端骨节(骨骼)->m_变换.position), 骨骼方向);
			f_从骨头取末端骨节(骨骼)->m_isUpdate = true;
		}
		else {
			骨骼方向 = {};
		}

		f_将超出长度范围的骨节移动到范围内(骨骼, 骨节, depth + 1, 骨骼长度, 移动修正 + 骨骼方向);
	}
}


static void f_IK虚线变换更新(S_物体* ob, Mat44f* 矩阵, const Mat44f* 父级变换) {
	float64 t = ob->g_当前帧 + ob->m_TimeOffset;

	vec3 loc = ob->m_变换.position;
	vec3 rot = ob->m_变换.rotation;
	vec3 scale = ob->m_变换.scale;


	if (S_物体::g_更新曲线关键帧) {
		if (ob->m_位置) {
			ob->m_变换.position = f_an_曲线值(ob->m_位置, t);
		}
		if (ob->m_旋转) {
			ob->m_变换.rotation = f_an_曲线值(ob->m_旋转, t);
		}
		if (ob->m_缩放) {
			ob->m_变换.scale = f_an_曲线值(ob->m_缩放, t);
		}
	}


	S_Mesh* me = f_ob_getMesh(ob, 0);
	S_骨架* 骨架 = f_ob_from骨架(static_cast<S_物体*>(ob->m_父对象));

	std::vector<S_VNT1> 顶点;
	std::vector<uint32> 索引;
	for (uint32 i = 0; i < 骨架->m_IK数量; ++i) {
		S_VNT1 v{};
		v.vert = f_ob_from骨骼(骨架->m_IK[i]->m_始端)->m_骨节B->m_变换.position;
		顶点.push_back(v);

		v.vert = f_ob_from骨骼(骨架->m_IK[i]->m_末端)->m_骨节B->m_变换.position;
		顶点.push_back(v);

		索引.push_back(i * 2);
		索引.push_back(i * 2 + 1);
	}
	f_mesh_fill顶点数据(me, 顶点);
	f_me_fill索引(me, 索引);


	Mat44f mat = f_mat44_构建XYZ变换矩阵({ loc, rot, scale });

	if (父级变换) {
		mat = (*父级变换) * mat;
	}
	(*矩阵) = mat;
}




void on_引用物体节点_联动创建(C_节点基类* self, std::vector<C_节点基类*> nodes) {
	C_引用物体节点* node = (C_引用物体节点*)self;

	if (nodes.size()) {
		S_物体* 物体 = nodes.front()->f_虚拟体();
		if(物体) f_prop_LineStr(node->m_查找名称) = 物体->m_Name;
	}
}


C_物体节点::C_物体节点(S_设备环境& ctx) : C_节点基类("物体节点") {
	f_setWName(u"物体节点");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建UI32插座_I(u"数量");
	DEF_创建物体_1D插座_O(u"物体");

	m_物体类型 = f_prop_创建物体类型属性数据();
	m_物体类型.m_私有 = true;
	f_prop_enum(m_物体类型) = 1;

	m_物体显示模式 = f_alloc_FlagBitsEnumProp(nullptr, *S_节点数据::g_物体显示模式项_光追, u"显示模式", 391);
	m_物体显示模式.m_私有 = true;
	
	m_物体名称 = f_alloc_LineStrProp(nullptr, u"物体名称");
	m_物体名称.m_私有 = true;

	f_prop_LineStr(m_物体名称) = u"物体集_";
}

C_物体节点::~C_物体节点() {
	f_prop_Release(m_物体类型);
	f_prop_Release(m_物体显示模式);
	f_prop_Release(m_物体名称);

	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);

	for (uint32 i = 0; i < objs->count; ++i) {
		f_NodeCtx_get默认场景()->f_remove物体(objs->ptr_userData[i], E_场景物体容器类型::e_集合);
		f_ob_销毁(objs->ptr_userData[i]);
	}
}

bool C_物体节点::f_update() {
	uint32 num = DEF_UI32插座数据(f_get输入插座(1));
	auto* obs = DEF_物体插座_1D数据(f_get输出插座(1), 0);

	E_物体类型 物体类型  = f_prop_物体类型(m_物体类型);
	
	f_node_创建模型物体组(obs, num, 物体类型, m_Ctx);


	for (uint32 i = 0; i < obs->count; ++i) {
		uint32 fb = f_prop_UI32位域枚举(m_物体显示模式);
		obs->ptr_userData[i]->m_视口显示模式 = (obs->ptr_userData[i]->m_视口显示模式 & 0xffff0000) | fb;
	}
	
	return false;
}

S_动画曲线组* C_物体节点::f_getAN曲线() {
	
	return nullptr;
}

void C_物体节点::f_Show(bool open) {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1));
	for (uint32 i = 0; i < objs->count; ++i) {
		objs->ptr_userData[i]->m_显示 = open;
	}
}

void C_物体节点::f_删除() {
	auto* obs = DEF_物体插座_1D数据(f_get输出插座(1), 0);

	f_node_物体从主场景中移除(obs);
	f_node_从全局容器移除物体(obs);
}

void C_物体节点::f_读取(FILE * f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
		
		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
			uint32 num = 0;
			下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, num);
			下一次读取数据指针 = f_prop_Load(m_物体类型, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_物体显示模式, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_物体名称, 下一次读取数据指针);

			switch (f_prop_enum(m_物体类型)) {
				case 0: {
					break;
				}
				case 1: {
					f_node_创建模型物体组(objs, num, E_物体类型::t_网格物体, m_Ctx);
					break;
				}
				case 2: {
					f_node_创建模型物体组(objs, num, E_物体类型::t_多边形, m_Ctx);
					break;
				}
				default:
					break;
			}

			下一次读取数据指针 = f_ob_Load多物体(objs, 下一次读取数据指针, m_Ctx);
		}
		else if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			uint32 num = 0;
			下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, num);
			下一次读取数据指针 = f_prop_Load(m_物体类型, 下一次读取数据指针);

			switch (f_prop_enum(m_物体类型)) {
				case 0: {
					break;
				}
				case 1: {
					f_node_创建模型物体组(objs, num, E_物体类型::t_网格物体, m_Ctx);
					break;
				}
				case 2: {
					f_node_创建模型物体组(objs, num, E_物体类型::t_多边形, m_Ctx);
					break;
				}
				default:
					break;
			}

			下一次读取数据指针 = f_ob_Load多物体(objs, 下一次读取数据指针, m_Ctx);
		}
	}
	free(文件块.m_data);
}

void C_物体节点::f_写入(FILE * f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	auto* obs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_文件块_写数据块(块, (uint32)obs->count);
	f_prop_Save(m_物体类型, 块);
	f_prop_Save(m_物体显示模式, 块);
	f_prop_Save(m_物体名称, 块);

	f_ob_Save多物体(obs, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体节点(ctx);
}

C_节点基类* f_node_加载物体节点(S_设备环境& ctx, FILE* f) {
	C_物体节点* node = new C_物体节点(ctx);

	return node;
}

void f_node_保存物体节点(C_节点基类* n, FILE* f) {
	C_物体节点* node = dynamic_cast<C_物体节点*>(n);
}




C_引用物体节点::C_引用物体节点(S_设备环境& ctx) : C_节点基类(DEF_引用物体节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"引用物体");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_O(u"物体");

	m_自定义更新方式 = true;


	m_引用查找方式 = f_alloc_EnumProp(nullptr, {
		{u"名称查找", u""},
	}, u"引用查找方式");
	m_引用查找方式.m_私有 = true;


	m_查找名称 = f_alloc_LineStrProp(nullptr, u"引用物体名称");
	m_查找名称.m_私有 = true;
	m_物体名称 = {};


	mf_节点联动创建 = on_引用物体节点_联动创建;
}

C_引用物体节点::~C_引用物体节点() {
	f_prop_Release(m_引用查找方式);
	if (m_物体名称.m_Type) {
		f_prop_Release(m_物体名称);
	}
	f_prop_Release(m_查找名称);
}

bool C_引用物体节点::f_update() {
	auto& 查找名称 = f_prop_LineStr(m_查找名称);

	auto* ob = f_node_从全局物体容器查找物体(查找名称);

	if (ob) {
		f_get输出插座(1)->f_setData(ob);
		m_name = ob->m_Name;
	}
	
	return false;
}

S_动画曲线组* C_引用物体节点::f_getAN曲线() {
	return nullptr;
}

void C_引用物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_引用查找方式, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_查找名称, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_引用物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_引用查找方式, 块);
	f_prop_Save(m_查找名称, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建引用物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_引用物体节点(ctx);
}

C_节点基类* f_node_加载引用物体节点(S_设备环境& ctx, FILE* f) {
	C_引用物体节点* node = new C_引用物体节点(ctx);
	return node;
}

void f_node_保存引用物体节点(C_节点基类* n, FILE* f) {
	C_引用物体节点* node = dynamic_cast<C_引用物体节点*>(n);
}




C_物体虚拟体节点::C_物体虚拟体节点(S_设备环境& ctx) : C_节点基类(DEF_物体虚拟体节点, E_节点类型::e_节点Type_虚拟体) {
	f_setWName(u"虚拟体");
	m_Ctx = ctx;

	//m_Ob = f_node_创建虚拟体(ctx);
	m_Ob = f_node_create创建十字叉虚拟体(ctx);
	f_NodeCtx_录物体类节点(this, m_Ob);
	m_Ob->m_变换.scale = {0.2,0.2,0.2};
	m_Ob->m_Name = u"虚拟体";

	f_node_物体添加到主场景(m_Ob);
	f_node_物体添加到全局容器(m_Ob);



	m_动画曲线列表 = f_an_创建曲线层();

	C_插座基类* socket;
	DEF_创建物体插座_O(u"物体");


	m_虚拟体网格类型 = f_alloc_EnumProp(nullptr, 
	{
		{u"立方体", u"立体线框"}, 
		{u"球体", u"球体"},
		{u"十字叉", u"球体"},
	}, 
	u"显示类型");
	m_虚拟体网格类型.m_私有 = true;
	f_prop_enum(m_虚拟体网格类型) = 0;

	m_Ob->m_颜色 = { 50,255,50,255 };
}

C_物体虚拟体节点::~C_物体虚拟体节点() {
	f_node_物体从主场景中移除(m_Ob);
	f_node_从全局容器移除物体(m_Ob);

	f_ob_销毁(m_Ob);
}

bool C_物体虚拟体节点::f_update() {

	switch (f_prop_enum(m_虚拟体网格类型)) {
	case 0:
		f_node_虚拟体_设置立方体虚拟网格(m_Ob);
		break;

	case 1:
		f_node_虚拟体_设置球体虚拟网格(m_Ob);
		break;

	case 2:
		f_node_虚拟体_设置十字叉虚拟网格(m_Ob);
		break;
	}
	
	for (uint32 i = 0; i < m_Ob->m_DataNum; ++i) {
		f_ob_getMesh(m_Ob, i)->m_Color = {50,255,50,255};
	}

	f_get输出插座(1)->f_setData(m_Ob);
	return false;
}

S_动画曲线组* C_物体虚拟体节点::f_getAN曲线() {
	f_an_清除曲线通道(m_动画曲线列表);

	if (m_Ob->m_位置) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_位置);
	}
	if (m_Ob->m_旋转) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_旋转);
	}
	if (m_Ob->m_缩放) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_缩放);
	}
	return m_动画曲线列表;
}

S_物体* C_物体虚拟体节点::f_虚拟体() {
	return m_Ob;
}

void C_物体虚拟体节点::f_删除() {
	m_Ob->m_显示 = false;
	f_node_物体从主场景中移除(m_Ob);
	f_node_从全局容器移除物体(m_Ob);
	//f_node_移除虚拟体(m_Ob);
}

void C_物体虚拟体节点::f_回收() {
	m_Ob->m_显示 = true;
	f_node_物体添加到主场景(m_Ob);
	f_node_物体添加到全局容器(m_Ob);
}

void C_物体虚拟体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_虚拟体网格类型, 下一次读取数据指针);
			//下一次读取数据指针 = f_ob_Load物体(m_Ob, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_物体虚拟体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_虚拟体网格类型, 块);
	f_ob_Save物体(m_Ob, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建物体虚拟体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体虚拟体节点(ctx);
}

C_节点基类* f_node_加载物体虚拟体节点(S_设备环境& ctx, FILE* f) {
	C_物体虚拟体节点* node = new C_物体虚拟体节点(ctx);
	return node;
}

void f_node_保存物体虚拟体节点(C_节点基类* n, FILE* f) {
	C_物体虚拟体节点* node = dynamic_cast<C_物体虚拟体节点*>(n);
}







C_天空节点::C_天空节点(S_设备环境& ctx) : C_节点基类(DEF_天空节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"天空");
	m_Ctx = ctx;

	m_Ob = f_ob_创建(ctx, E_物体类型::t_网格物体);
	f_node_构建物体模型(m_Ob, ctx);
	f_ob_创建天空网格(ctx, m_Ob, E_物体网格元素类型::e_MT_纹理);

	f_NodeCtx_录物体类节点(this, m_Ob);
	m_Ob->m_变换.scale =_Vec3(5000);
	m_Ob->m_Name = u"天空";
	m_Ob->m_可拾取 = false;

	f_node_物体添加到主场景(m_Ob);
	f_node_物体添加到全局容器(m_Ob);



	m_动画曲线列表 = f_an_创建曲线层();

	C_插座基类* socket;
	DEF_创建F32插座_I(u"时间", nullptr);
	DEF_创建物体插座_O(u"物体");


	m_天空类型 = f_alloc_EnumProp(nullptr,
		{
			{u"球体", u"球体"},
			{u"立方体", u"立体线框"},
		},
		u"类型");
	m_天空类型.m_私有 = true;

	m_天空大小 = f_alloc_F32Prop(nullptr, u"半径", 5000);
	m_天空大小.m_私有 = true;

	m_Ob->m_颜色 = { 50,255,50,255 };
}

C_天空节点::~C_天空节点() {
	f_node_物体从主场景中移除(m_Ob);
	f_node_从全局容器移除物体(m_Ob);

	f_ob_销毁(m_Ob);
}

bool C_天空节点::f_update() {
	f_ob_setScale(m_Ob, _Vec3(-f_prop_F32(m_天空大小)));

	f_get输出插座(1)->f_setData(m_Ob);
	return false;
}

S_物体* C_天空节点::f_虚拟体() {
	return m_Ob;
}

void C_天空节点::f_删除() {
	m_Ob->m_显示 = false;
	f_node_物体从主场景中移除(m_Ob);
	f_node_从全局容器移除物体(m_Ob);
}

void C_天空节点::f_回收() {
	m_Ob->m_显示 = true;
	f_node_物体添加到主场景(m_Ob);
	f_node_物体添加到全局容器(m_Ob);
}

void C_天空节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_天空类型, 下一次读取数据指针);
			//下一次读取数据指针 = f_ob_Load物体(m_Ob, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_天空节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_天空类型, 块);
	f_ob_Save物体(m_Ob, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建天空节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_天空节点(ctx);
}

C_节点基类* f_node_加载天空节点(S_设备环境& ctx, FILE* f) {
	C_天空节点* node = new C_天空节点(ctx);
	return node;
}

void f_node_保存天空节点(C_节点基类* n, FILE* f) {
	C_天空节点* node = dynamic_cast<C_天空节点*>(n);
}




C_取物体节点::C_取物体节点(S_设备环境& ctx) : C_节点基类(DEF_取物体节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"取物体");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Str插座_I(u"名称");
	DEF_创建物体插座_O(u"物体");


	m_过滤类型 = f_alloc_EnumProp(nullptr, {
	    {u"网格"}, 
		{u"平行光"}, 
		{u"点光源"},
		{u"区域光"},
		{u"聚光灯"},
		{u"摄像机"},
		{u"虚拟体"},
	}, u"类型");
	m_过滤类型.m_私有 = true;

	m_动画曲线列表 = f_an_创建曲线层();
}

C_取物体节点::~C_取物体节点() {
	f_prop_Release(m_过滤类型);
}

bool C_取物体节点::f_update() {
	auto* socket = f_get输入插座(1);

	return false;
}

S_动画曲线组* C_取物体节点::f_getAN曲线() {
	auto* m_Ob = DEF_物体插座数据(f_get输出插座(1), 0);

	f_an_清除曲线通道(m_动画曲线列表);
	if (m_Ob) {
		if (m_Ob->m_位置) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_位置);
		}
		if (m_Ob->m_旋转) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_旋转);
		}
		if (m_Ob->m_缩放) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_缩放);
		}
	}
	
	return m_动画曲线列表;
}

void C_取物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_过滤类型, f);
}

void C_取物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_过滤类型, f);
}

C_节点基类* f_node_创建取物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_取物体节点(ctx);
}
C_节点基类* f_node_加载取物体节点(S_设备环境& ctx, FILE* f) {
	C_取物体节点* node = new C_取物体节点(ctx);
	return node;
}
void f_node_保存取物体节点(C_节点基类* n, FILE* f) {
	C_取物体节点* node = dynamic_cast<C_取物体节点*>(n);
}



C_设置物体渲染属性节点::C_设置物体渲染属性节点(S_设备环境& ctx) : C_节点基类(DEF_设置物体渲染属性节点) {
	f_setWName(u"渲染属性");
	m_Ctx = ctx;

	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建物体_1D插座_O(u"物体");
}

C_设置物体渲染属性节点::~C_设置物体渲染属性节点() {
}

bool C_设置物体渲染属性节点::f_update() {
	return false;
}

S_动画曲线组* C_设置物体渲染属性节点::f_getAN曲线() {
	return nullptr;
}

void C_设置物体渲染属性节点::f_读取(FILE* f) {
}

void C_设置物体渲染属性节点::f_写入(FILE* f) {
}

C_节点基类* f_node_创建设置物体渲染属性节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体渲染属性节点(ctx);
}

C_节点基类* f_node_加载设置物体渲染属性节点(S_设备环境& ctx, FILE* f) {
	C_设置物体渲染属性节点* node = new C_设置物体渲染属性节点(ctx);
	return node;
}

void f_node_保存设置物体渲染属性节点(C_节点基类* n, FILE* f) {
	C_设置物体渲染属性节点* node = dynamic_cast<C_设置物体渲染属性节点*>(n);
}



C_查找子物体节点::C_查找子物体节点(S_设备环境 & ctx) : C_节点基类(DEF_查找子物体节点) {
	f_setWName(u"查找子物体");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_I(u"父物体");
	DEF_创建Str插座_I(u"名称");
	DEF_创建物体插座_O(u"子物体");

	m_查找类型 = f_alloc_EnumProp(nullptr, {
		{u"网格"}, 
		{u"平行光"}, 
		{u"点光源"},
		{u"区域光"},
		{u"聚光灯"},
		{u"摄像机"},
		{u"虚拟体"},
		}, u"类型");
	m_查找类型.m_私有 = true;

	m_动画曲线列表 = f_an_创建曲线层();
}

C_查找子物体节点::~C_查找子物体节点() {
	f_prop_Release(m_查找类型);
}

bool C_查找子物体节点::f_update() {
	auto* 物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	E_物体类型 类型 = f_ob_以名称索引取类型(f_prop_enum(m_查找类型));
	if(物体) 物体 = f_ob_以类型查找子物体(物体, 类型);
	f_get输出插座(1)->f_setData(物体);
	return false;
}

S_动画曲线组* C_查找子物体节点::f_getAN曲线() {
	auto* m_Ob = DEF_物体插座数据(f_get输出插座(1), 0);

	f_an_清除曲线通道(m_动画曲线列表);
	if (m_Ob) {
		if (m_Ob->m_位置) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_位置);
		}
		if (m_Ob->m_旋转) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_旋转);
		}
		if (m_Ob->m_缩放) {
			f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_缩放);
		}
	}
	
	return m_动画曲线列表;
}

void C_查找子物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_查找类型, f);
}

void C_查找子物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_查找类型, f);
}

C_节点基类* f_node_创建查找子物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_查找子物体节点(ctx);
}

C_节点基类* f_node_加载查找子物体节点(S_设备环境& ctx, FILE* f) {
	C_查找子物体节点* node = new C_查找子物体节点(ctx);
	return node;
}

void f_node_保存查找子物体节点(C_节点基类* n, FILE* f) {
	C_查找子物体节点* node = dynamic_cast<C_查找子物体节点*>(n);
}




C_物体父子关系节点::C_物体父子关系节点(S_设备环境& ctx) : C_节点基类("物体父子关系节点") {
	f_setWName(u"父子关系");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_I(u"物体");
	DEF_创建物体_1D插座_I(u"子物体");
	DEF_创建物体插座_O(u"物体");

	m_父子变换关系类型 = f_alloc_EnumProp(nullptr, {
		{u"继承", u""},
		{u"保持", u""},
	}, u"相对变换类型");
	m_父子变换关系类型.m_私有 = true;
}

C_物体父子关系节点::~C_物体父子关系节点() {
	f_prop_Release(m_父子变换关系类型);
}

bool C_物体父子关系节点::f_update() {
	auto inData1 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto inData2 = DEF_物体插座_1D数据(f_get输入插座(2), 0);

	f_ob_清除子物体(inData1);

	//f_mat44_Inverse
	vec3 中心 = {};
	for (uint32 i = 0; i < inData2->count; ++i) {
		//vec3 l = f_ob_get全局坐标(inData2->ptr_userData[i], inData2->ptr_userData[i]->m_实例ID);
		vec3 l = inData2->ptr_userData[i]->f_get位置();

		中心 += l;
	}
	中心 /= inData2->count;

	for (uint32 i = 0; i < inData2->count; ++i) {
		f_ob_add子物体(inData1, inData2->ptr_userData[i]);

		inData2->ptr_userData[i]->m_父级变换关系 = E_父级变换关系(f_prop_enum(m_父子变换关系类型));
		inData2->ptr_userData[i]->m_isUpdate = true;
	}

	//inData1->m_父级变换关系 = E_父级变换关系(f_prop_enum(m_父子变换关系类型));
	inData1->m_isUpdate = true;
	f_get输出插座(1)->f_setData(inData1);
	return false;
}

void C_物体父子关系节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_父子变换关系类型, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_物体父子关系节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_父子变换关系类型, 块);
	//f_ob_Save物体(m_Ob, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建物体父子关系节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体父子关系节点(ctx);
}
C_节点基类* f_node_加载物体父子关系节点(S_设备环境& ctx, FILE* f) {
	C_物体父子关系节点* node = new C_物体父子关系节点(ctx);
	return node;
}

void f_node_保存物体父子关系节点(C_节点基类* n, FILE* f) {
	C_物体父子关系节点* node = dynamic_cast<C_物体父子关系节点*>(n);
}




C_设置物体数据节点::C_设置物体数据节点(S_设备环境& ctx) : C_节点基类("设置物体数据节点") {
	f_setWName(u"设置物体数据");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_Array1D插座_I(u"物体");
	DEF_创建引用插座_I(u"数据");

	DEF_创建物体_Array1D插座_O(u"物体");
}

C_设置物体数据节点::~C_设置物体数据节点() {
}

bool C_设置物体数据节点::f_update() {
	auto& inData1 = *DEF_物体插座_Array1D数据(f_get输入插座(1), 0);
	auto& inData2 = *DEF_引用插座数据(f_get输入插座(2), 0);

	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	objs = inData1;

	uint32 num = inData1.size();
	auto* ob_ptr = inData1.data();
	switch (inData2.m_Type) {
	case E_值类型::e_Type_Mesh: {
		auto mesh = DEF_引用转MESH(inData2);
		for (uint32 i = 0; i < num; ++i) {
			f_ob_set数据(ob_ptr[i], mesh);
			f_ob_set数据(ob_ptr[i], mesh, 1);
			f_ob_set数据(ob_ptr[i], mesh, 2);
			ob_ptr[i]->m_Type = E_物体类型::t_网格物体;

			f_NodeCtx_录物体类节点(this, ob_ptr[i]);
		}
		break;
	}
	case E_值类型::e_Type_Mesh_1D: {
		auto& mesh = *DEF_引用转MESH_1D(inData2);
		uint32 mesh_num = mesh.size();
		auto* mesh_ptr = mesh.data();
		if (mesh_num >= num) {
			for (uint32 i = 0; i < num; ++i) {
				f_ob_set数据槽数量(ob_ptr[i], 3);
				f_ob_set数据(ob_ptr[i], mesh_ptr[i]);
				f_ob_set数据(ob_ptr[i], f_surface_创建实例(mesh_ptr[i]), 1);
				f_ob_set数据(ob_ptr[i], f_surface_创建实例(mesh_ptr[i]), 2);

				f_ob_set材质(ob_ptr[i], f_NodeCtx_get基本光照面材质(), 1);
				f_ob_set材质(ob_ptr[i], f_NodeCtx_get基本光照线材质(), 2);

				ob_ptr[i]->m_Type = E_物体类型::t_网格物体;
				f_NodeCtx_录物体类节点(this, ob_ptr[i]);
			}
		}
		else {
			auto mesh_l1 = f_surface_创建实例(mesh_ptr[0]);
			auto mesh_l2 = f_surface_创建实例(mesh_ptr[0]);
			for (uint32 i = 0; i < num; ++i) {
				f_ob_set数据(ob_ptr[i], mesh_ptr[0]);
				f_ob_set数据(ob_ptr[i], mesh_l1, 1);
				f_ob_set数据(ob_ptr[i], mesh_l2, 2);

				f_ob_set材质(ob_ptr[i], f_NodeCtx_get基本光照面材质(), 1);
				f_ob_set材质(ob_ptr[i], f_NodeCtx_get基本光照线材质(), 2);

				ob_ptr[i]->m_Type = E_物体类型::t_网格物体;
				f_NodeCtx_录物体类节点(this, ob_ptr[i]);
			}
		}
		break;
	}
	case E_值类型::e_Type_Object: {
		auto* mesh = f_ob_getMesh(DEF_引用转物体(inData2));
		auto* mesh1 = f_ob_getMesh(DEF_引用转物体(inData2), 1);
		auto* mesh2 = f_ob_getMesh(DEF_引用转物体(inData2), 2);
		for (uint32 i = 0; i < num; ++i) {
			f_ob_set数据(ob_ptr[i], mesh);
			f_ob_set数据(ob_ptr[i], mesh1, 1);
			f_ob_set数据(ob_ptr[i], mesh2, 2);
			ob_ptr[i]->m_Type = E_物体类型::t_网格物体;

			f_NodeCtx_录物体类节点(this, ob_ptr[i]);
		}

		break;
	}
	case E_值类型::e_Type_Object_Array1D: {
		auto& 数据物体 = *DEF_引用转物体_1D(inData2);
		uint32 mesh_num = 数据物体.size();
		if (mesh_num >= num) {
			for (uint32 i = 0; i < num; ++i) {

			}
		}
		else {

		}
		break;
	}
	default:
		break;
	}
	
	return false;
}

S_物体* C_设置物体数据节点::f_虚拟体() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	if(objs.size()) return objs.front();
	return nullptr;
}

void C_设置物体数据节点::f_删除() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	for (auto& ob : objs) {
		S_节点数据::m_全局物体set.erase(ob);
	}
}

void C_设置物体数据节点::f_回收() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输出插座(1), 0);
	for (auto& ob : objs) {
		S_节点数据::m_全局物体set.insert(ob);
	}
}

C_节点基类* f_node_加载设置物体数据节点(S_设备环境& ctx, FILE* f) {
	C_设置物体数据节点* node = new C_设置物体数据节点(ctx);
	return node;
}
void f_node_保存设置物体数据节点(C_节点基类* n, FILE* f) {
	C_设置物体数据节点* node = dynamic_cast<C_设置物体数据节点*>(n);
}



C_取物体属性节点::C_取物体属性节点(S_设备环境& ctx) : C_节点基类("取物体属性节点", E_节点类型::e_节点Type_物体) {
	f_setWName(u"取物体属性");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_Array1D插座_I(u"对象");
	DEF_创建Mat4X4_Array1D插座_O(u"矩阵");
	DEF_创建变换_1D插座_O(u"变换");
}

C_取物体属性节点::~C_取物体属性节点() {
}

bool C_取物体属性节点::f_update() {
	auto& objs = *DEF_物体插座_Array1D数据(f_get输入插座(1), 0);
	auto& mats = *DEF_Mat44_Array1D插座数据(f_get输出插座(1), 0);
	auto& tranforms = *DEF_变换_1D插座数据(f_get输出插座(2), 0);

	uint32 num = objs.size();
	mats.resize(num);
	tranforms.resize(num);

	auto* ob_ptr = objs.data();
	auto* mat_ptr = mats.data();
	auto* tranform_ptr = tranforms.data();
	for (uint32 i = 0; i < num; ++i) {
		mat_ptr[i] = ob_ptr[i]->f_get矩阵2();
		tranform_ptr[i] = ob_ptr[i]->m_变换;
	}
	return false;
}

C_节点基类* f_node_加载取物体属性节点(S_设备环境& ctx, FILE* f) {
	C_取物体属性节点* node = new C_取物体属性节点(ctx);
	return node;
}

void f_node_保存取物体属性节点(C_节点基类* n, FILE* f) {
	C_取物体属性节点* node = dynamic_cast<C_取物体属性节点*>(n);
}





C_骨头节点::C_骨头节点(S_设备环境& ctx) : C_节点基类("骨头节点", E_节点类型::e_节点Type_骨头) {
	f_setWName(u"骨头");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"父骨头");
	DEF_创建IK插座_I(u"IK");
	DEF_创建物体插座_O(u"骨头");
	f_get输入插座(1)->f_set多输入();

	m_骨头物体 = f_ob_创建骨骼(nullptr, ctx);
	


	S_骨骼* 骨骼 = f_ob_from骨骼(m_骨头物体);
	骨骼->m_长度 = 1.0;

	f_NodeCtx_录物体类节点(this);
	f_NodeCtx_录物体类节点(this, m_骨头物体);
	f_NodeCtx_录物体类节点(this, 骨骼->m_骨节B);
	//m_骨头->f_set位置(DEF_骨骼朝向);

	f_node_create骨骼虚拟体网格(m_骨头物体);
	f_node_物体添加到主场景(m_骨头物体);
	f_node_物体添加到全局容器(m_骨头物体);

	
	f_ob_getMesh(m_骨头物体, 0)->m_拾取 = false;


	m_封套 = f_node_创建圆柱封套虚拟体(m_Ctx);
	
	//f_node_物体添加到主场景(m_封套);
	//static int32 x = 0;
	//m_封套->m_变换.location.x += x;
	//x += 2;


	m_末端骨节 = nullptr;

	m_封套长度 = f_alloc_F32Prop(nullptr, u"封套长度");
	m_封套长度.m_私有 = true;

	m_封套S内半径 = f_alloc_F32Prop(&骨骼->m_封套S内半径, u"S内半径");
	m_封套S内半径.m_私有 = true;

	m_封套E内半径 = f_alloc_F32Prop(&骨骼->m_封套E内半径, u"E内半径");
	m_封套E内半径.m_私有 = true;

	m_封套S外半径 = f_alloc_F32Prop(&骨骼->m_封套S外半径, u"S外半径");
	m_封套S外半径.m_私有 = true;

	m_封套E外半径 = f_alloc_F32Prop(&骨骼->m_封套E外半径, u"E外半径");
	m_封套E外半径.m_私有 = true;


	m_自动封套大小 = f_alloc_BoolProp(&骨骼->m_自动封套大小, u"E外半径");
	m_自动封套大小.m_私有 = true;


	f_prop_F32(m_封套S内半径) = 0.25;
	f_prop_F32(m_封套E内半径) = 0.25;

	f_prop_F32(m_封套S外半径) = 0.5;
	f_prop_F32(m_封套E外半径) = 0.5;

	f_prop_Bool(m_自动封套大小) = true;
}

C_骨头节点::~C_骨头节点() {
	f_node_物体从主场景中移除(m_骨头物体);
	f_node_从全局容器移除物体(m_骨头物体);

	f_prop_Release(m_封套长度);
	f_prop_Release(m_封套S内半径);
	f_prop_Release(m_封套E内半径);
	f_prop_Release(m_封套S外半径);
	f_prop_Release(m_封套E外半径);

	f_prop_Release(m_自动封套大小);


	f_ob_销毁(m_封套);
}

bool C_骨头节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	//if (socket1->m_有新数据) {
	
	f_ob_clear子物体(m_骨头物体);
	m_骨头物体->m_骨架 = nullptr;

	S_骨骼* 骨骼 = f_ob_from骨骼(m_骨头物体);
	S_骨节* 骨节 = f_ob_from骨节(m_骨头物体);
	骨骼->m_骨节B->m_变换.position = 骨节->m_骨节初始尾坐标;
	骨骼->m_封套范围线 = m_封套;
	//骨骼->m_对称物体 = nullptr;
	//骨骼->m_对称偏移 = {};
	//骨骼->m_对称方向 = -1;

	
	if (f_get输入插座(1)->f_isLink()) {
		
		骨骼->m_IK关联数量 = 0;
		
		uint32 多输入数量 = socket1->f_getLinkNum();
		for (uint32 i = 0; i < 多输入数量; ++i) {
			auto* inData = (S_OBArray*)(socket1->f_getData(i));
			if (inData->count == 0) continue;

			uint32 总数量 = 0;
			for (uint32 i = 0; i < inData->count; ++i) {
				f_ob_add子物体(m_骨头物体, inData->ptr_userData[i]);
			}
		}
		

		//if (m_末端骨节) {
		//	f_node_物体从全局容器移除(m_末端骨节);
		//}
	}
	f_ob_add子物体(m_骨头物体, m_封套);

	auto& et0 = f_mesh_get网格元素绘制属性(f_ob_getMesh(m_封套, 0));
	et0.m_XScale = et0.m_YScale = et0.m_ZScale = f_prop_F32(m_封套S内半径);
	et0.m_ZScale = -et0.m_ZScale;
	et0.m_TransformMode = DEF_MESH_LINE_TRANFORMTYPEMODEL_CenterZoom;
	
	auto& et1 = f_mesh_get网格元素绘制属性(f_ob_getMesh(m_封套, 1));
	et1.m_XScale = et1.m_YScale = et1.m_ZScale = f_prop_F32(m_封套E内半径);
	et1.m_ZMove = 骨骼->m_长度;
	et1.m_TransformMode = DEF_MESH_LINE_TRANFORMTYPEMODEL_CenterZoom;
	
	
	auto& et2 = f_mesh_get网格元素绘制属性(f_ob_getMesh(m_封套, 2));
	et2.m_XScale = et2.m_YScale = et2.m_ZScale = f_prop_F32(m_封套S外半径);
	et2.m_ZScale = -et2.m_ZScale;
	et2.m_TransformMode = DEF_MESH_LINE_TRANFORMTYPEMODEL_CenterZoom;
	
	auto& et3 = f_mesh_get网格元素绘制属性(f_ob_getMesh(m_封套, 3));
	et3.m_XScale = et3.m_YScale = et3.m_ZScale = f_prop_F32(m_封套E外半径);
	et3.m_ZMove = 骨骼->m_长度;
	et3.m_TransformMode = DEF_MESH_LINE_TRANFORMTYPEMODEL_CenterZoom;
	
	
	
	f_ob_set颜色2(m_封套, { 255,0,0,255 }, 0, 0);
	f_ob_set颜色2(m_封套, { 255,0,0,255 }, 0, 1);
	f_ob_set颜色2(m_封套, { 0,0,255,255 }, 0, 2);
	f_ob_set颜色2(m_封套, { 0,0,255,255 }, 0, 3);
	
	f_ob_set颜色2(m_封套, { 255,0,0,255 }, 0, 4);
	

	f_ob_getMesh(m_封套, 0)->m_Color = { 255,0,0,255 };
	f_ob_getMesh(m_封套, 1)->m_Color = { 255,0,0,255 };
	f_ob_getMesh(m_封套, 2)->m_Color = { 0,0,255,255 };
	f_ob_getMesh(m_封套, 3)->m_Color = { 0,0,255,255 };
	
	f_ob_getMesh(m_封套, 4)->m_Color = { 255,0,0,255 };


	auto 桶网格 = f_ob_getMesh(m_封套, 4);
	auto& et4 = f_mesh_get网格元素绘制属性(桶网格);
	桶网格->m_片源着色模式 = DEF_DrawType_Normal_To_Col;
	
	static std::vector<S_VNT1> 顶点{
		{ {1, 0, 0}, {1,0,0}, {} },
		{ {0, 1, 0}, {1,0,0}, {} },
		{ {-1, 0, 0}, {0,0,1}, {} },
		{ {0, -1, 0}, {0,0,1}, {} },
		
	};
	
	auto* vert = f_buf_VNT_ptr(*桶网格->m_顶点);
	for (uint32 i = 0; i < 4; ++i) {
		vert[i].vert = 顶点[i].vert * f_prop_F32(m_封套S内半径);
		vert[i + 4].vert = 顶点[i].vert * f_prop_F32(m_封套E内半径);
		vert[i + 4].vert.z = 骨骼->m_长度;
	
		vert[i + 8].vert = 顶点[i].vert * f_prop_F32(m_封套S外半径);
		vert[i + 12].vert = 顶点[i].vert * f_prop_F32(m_封套E外半径);
		vert[i + 12].vert.z = 骨骼->m_长度;
	}



	S_骨骼IK* IK = DEF_IK插座数据(f_get输入插座(2));
	//S_物体* IK = DEF_物体插座数据(f_get输入插座(2));
	if (IK) {
		骨骼->m_IK = IK;
		IK->m_末端 = m_骨头物体;
	}
	else {
		骨骼->m_IK = nullptr;
	}

	f_get输出插座(1)->f_setData(m_骨头物体);
	return false;
}

S_物体* C_骨头节点::f_虚拟体() {
	return m_骨头物体;
}

void C_骨头节点::f_删除() {
	//f_NodeCtx_get默认场景()->f_remove物体(m_骨头, E_场景物体容器类型::e_集合);
	f_node_物体从主场景中移除(m_骨头物体);
	f_node_从全局容器移除物体(m_骨头物体);
}

void C_骨头节点::f_回收() {
	//f_NodeCtx_get默认场景()->f_add物体({ m_骨头 }, E_场景物体容器类型::e_集合);
	f_node_物体添加到主场景(m_骨头物体);
	f_node_物体添加到全局容器(m_骨头物体);
}

void C_骨头节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			//下一次读取数据指针 = f_ob_Load物体(m_骨头物体, 下一次读取数据指针);
			下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, f_ob_from骨骼(m_骨头物体)->m_旋转);
			下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, f_ob_from骨骼(m_骨头物体)->m_长度);
			下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, f_ob_from骨节(f_ob_from骨骼(m_骨头物体)->m_骨节B)->m_骨节初始尾坐标);


			下一次读取数据指针 = f_prop_Load(m_封套S内半径, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_封套E内半径, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_封套S外半径, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_封套E外半径, 下一次读取数据指针);


			bool 根骨骼;
			下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, 根骨骼);
			if (根骨骼) {
				S_骨骼* 骨骼 = f_ob_from骨骼(m_骨头物体);

				骨骼->m_根骨骼 = f_创建骨骼物体(m_Ctx, false);
				//下一次读取数据指针 = f_ob_Load物体(骨骼->m_根骨骼, 下一次读取数据指针);
				下一次读取数据指针 = f_文件块_读数据块(下一次读取数据指针, f_ob_from骨节(f_ob_from骨骼(骨骼->m_根骨骼)->m_骨节B)->m_骨节初始尾坐标);
				//下一次读取数据指针 = f_文件块_读数据块(f_ob_from骨骼(骨骼->m_根骨骼)->m_长度, 下一次读取数据指针);
				f_ob_from骨骼(骨骼->m_根骨骼)->m_长度 = 0;

				//f_NodeCtx_录物体类节点(this, 骨骼->m_根骨骼);
				//f_NodeCtx_录物体类节点(this, f_ob_from骨骼(骨骼->m_根骨骼)->m_骨节B);
			}

			f_ob_from骨骼(m_骨头物体)->m_动态旋转 = f_ob_from骨骼(m_骨头物体)->m_旋转;
		}
	}
	free(文件块.m_data);
}

void C_骨头节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	S_骨骼* 骨骼 = f_ob_from骨骼(m_骨头物体);

	f_ob_Save物体(m_骨头物体, 块);
	f_文件块_写数据块(块, 骨骼->m_旋转);
	f_文件块_写数据块(块, 骨骼->m_长度);
	f_文件块_写数据块(块, f_ob_from骨节(骨骼->m_骨节B)->m_骨节初始尾坐标);

	f_prop_Save(m_封套S内半径, 块);
	f_prop_Save(m_封套E内半径, 块);
	f_prop_Save(m_封套S外半径, 块);
	f_prop_Save(m_封套E外半径, 块);

	//if (骨骼->m_IK) {
	//	f_文件块_写数据块(块, true);
	//	f_文件块_写数据块(块, 骨骼->m_IK->m_使用骨节坐标);
	//	f_文件块_写数据块(块, 骨骼->m_IK->m_深度);
	//	f_文件块_写数据块(块, 骨骼->m_IK->m_骨骼段数);
	//	f_文件块_写数据块(块, 骨骼->m_IK->m_迭代次数);
	//	f_ob_Save物体(骨骼->m_IK->m_末端坐标, 块);
	//}
	//else {
	//	f_文件块_写数据块(块, false);
	//}
	

	
	if (骨骼->m_根骨骼) {
		f_文件块_写数据块(块, true);

		f_ob_Save物体(骨骼->m_根骨骼, 块);
		f_文件块_写数据块(块, f_ob_from骨节(骨骼->m_骨节B)->m_骨节初始尾坐标);
	}
	else {
		f_文件块_写数据块(块, false);
	}

	
	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建骨头节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_骨头节点(ctx);
}

C_节点基类* f_node_加载骨头节点(S_设备环境& ctx, FILE* f) {
	C_骨头节点* node = new C_骨头节点(ctx);
	return node;
}

void f_node_保存骨头节点(C_节点基类* n, FILE* f) {
	C_骨头节点* node = dynamic_cast<C_骨头节点*>(n);
}





C_骨架节点::C_骨架节点(S_设备环境& ctx) : C_节点基类("骨骼节点", E_节点类型::e_节点Type_骨架) {
	f_setWName(u"骨架");
	m_Ctx = ctx;

	m_骨架 = f_ob_创建(m_Ctx, E_物体类型::t_骨架);
	m_虚线 = f_node_创建虚线(m_Ctx);
	m_虚线->mf_变换回调更新 = f_IK虚线变换更新;
	{
		f_node_物体添加到主场景(m_骨架);
		f_node_物体添加到全局容器(m_骨架);
	}
	
	m_编辑骨节物体 = f_ob_创建(m_Ctx, E_物体类型::t_骨节);
	f_node_create骨骼虚拟体网格(m_编辑骨节物体, false);


	
	//f_NodeCtx_录物体类节点(this, m_编辑骨节物体);
	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"根骨骼");
	DEF_创建引用插座_I(u"约束");
	DEF_创建骨架插座_O(u"骨架");
	f_get输入插座(1)->f_set多输入();
	f_get输入插座(2)->f_set多输入();
	
	f_NodeCtx_录物体类节点(this);


	m_前端显示 = f_alloc_BoolProp(nullptr, u"前端显示");
	m_前端显示.m_私有 = true;
	//m_更新方式 = e_节点更新_实时;

	
}

C_骨架节点::~C_骨架节点() {
	f_node_物体从主场景中移除(m_骨架);
	f_node_从全局容器移除物体(m_骨架);

	f_ob_clear子物体(m_骨架);

	f_ob_销毁(m_虚线);
	f_ob_销毁(m_骨架);
}

bool C_骨架节点::f_update() {
	S_骨架* 骨架 = f_ob_from骨架(m_骨架);
	

	auto* socket1 = f_get输入插座(1);
	//auto* 接入的插座 = socket1->f_get输出数据的插座();
	bool 有新数据 = socket1->f_get是否有输入新数据();
	if ((socket1 || socket1->m_有新数据)) {
		std::cout << "接入的插座->m_有新数据 = " << 有新数据 << std::endl;
		//m_删除的根骨头 = m_骨架->m_子物体;
		f_ob_clear子物体(m_骨架);
		

		uint32 多输入数量 = socket1->f_getLinkNum();

		for (uint32 i = 0; i < 多输入数量; ++i) {
			
			auto* inData = (S_OBArray*)(socket1->f_getData(i));
			if (inData->count == 0) continue;

			uint32 总数量 = 0;
			for (uint32 k = 0; k < inData->count; ++k) {
				if(inData->ptr_userData[k]->m_Type != E_物体类型::t_骨骼) continue;

				S_物体* 根骨骼;
				
				S_骨骼* 骨骼 = f_ob_from骨骼(inData->ptr_userData[k]);
				if (!骨骼->m_根骨骼) {
					根骨骼 = f_创建骨骼物体(m_Ctx, false);

					S_骨骼* 新骨骼 = f_ob_from骨骼(根骨骼);
					新骨骼->m_长度 = 0;

					骨骼->m_根骨骼 = 根骨骼;
					//骨骼->m_骨节B = f_ob_创建实例();
				}
				else {
					根骨骼 = 骨骼->m_根骨骼;
				}

				if (骨骼->m_对称物体) {
					auto* 对称骨骼 = f_ob_from骨骼(骨骼->m_对称物体);
					if (对称骨骼->m_根骨骼) {
						f_ob_from骨骼(根骨骼)->m_对称物体 = 对称骨骼->m_根骨骼;
						f_ob_from骨骼(根骨骼)->m_对称偏移 = 骨骼->m_对称偏移;
						f_ob_from骨骼(根骨骼)->m_对称方向 = 骨骼->m_对称方向;
						f_ob_from骨骼(根骨骼)->m_骨节B->m_可拾取 = false;
						根骨骼->m_可拾取 = false;
					}
				}
				else {
					根骨骼->m_可拾取 = true;
					f_ob_from骨骼(根骨骼)->m_骨节B->m_可拾取 = true;
				}


				f_NodeCtx_录物体类节点(this, 根骨骼);
				f_NodeCtx_录物体类节点(this, f_ob_from骨骼(根骨骼)->m_骨节B);

				f_ob_clear子物体(根骨骼);

				f_ob_add子物体(根骨骼, inData->ptr_userData[k]);
				f_ob_add子物体(m_骨架, 根骨骼);
			}
		}

		f_OE_构建骨骼(m_骨架, m_编辑骨节物体);
		
		
		f_ob_add子物体(m_骨架, m_虚线);
		f_ob_add子物体(m_骨架, m_编辑骨节物体);
		
		f_node_BE_从骨节更新骨骼(m_骨架);
		f_OE_更新骨骼封套范围线绘制(m_骨架);
		//f_node_BE_对称骨架(m_骨架);
		f_node_BE_更新骨骼网格属性(m_骨架);
	}


	if (f_prop_Bool(m_前端显示)) {
		auto* m = f_ob_getMesh(m_编辑骨节物体);
		
		f_递归设置骨骼网格深度绘制(m_骨架, 0.001);
		f_mesh_get网格元素绘制属性(m).m_DepthScale = 0.001;
	}
	else {
		auto* m = f_ob_getMesh(m_编辑骨节物体);
		
		f_递归设置骨骼网格深度绘制(m_骨架, 1);
		f_mesh_get网格元素绘制属性(m).m_DepthScale = 1;
	}

	bool 跳过更新约束 = false;

	switch (f_prop_enum(S_节点数据状态::g_骨架编辑模式)) {
		case E_骨骼编辑模式::e_骨架模式: {
			//f_NODE_BE_从骨骼更新骨节(m_骨架, m_骨骼物体->m_子物体.data(), m_骨节物体->m_子物体.data());
			//m_骨骼物体->m_isUpdate = true;
			//m_骨节物体->m_isUpdate = true;
			break;
		}
		case E_骨骼编辑模式::e_编辑模式: {
			//骨架->m_IK数量 = 0;
			//for (auto& e : m_骨架->m_子物体) {
			//	f_node_BE_从骨节构建骨骼(e, { 0,0,0,1 }, 0);
			//}
			跳过更新约束 = true;
			break;
		}
		case E_骨骼编辑模式::e_姿态模式: {
			//f_NODE_BE_从骨骼更新骨节(m_骨架物体, 骨骼长度, m_骨架物体->f_get矩阵2());
			break;
		}
		
	}


	//m_虚线->m_显示 = false;
	//if (跳过更新约束) return false;

	//auto* socket2 = f_get输入插座(2);
	//auto* 接入的插座2 = socket2->f_get输出数据的插座();
	//if ((!接入的插座2 || 接入的插座2->m_有新数据)) {

	//uint32 num = f_get输入插座(2)->f_getLinkNum();
	std::vector<S_骨骼IK*> 骨骼包含的IK;
	
	f_node_BE_get骨骼IK(骨骼包含的IK, m_骨架);
	uint32 num = 骨骼包含的IK.size();

	if (骨架->m_IK数量 != num) {
		if (骨架->m_IK) {
			free(骨架->m_IK);
		}
		骨架->m_IK = (S_骨骼IK**)calloc(num, sizeof(S_骨骼IK*));
	}
	骨架->m_IK数量 = 0;


	//计算IK
	S_Mesh* IK虚线 = f_ob_getMesh(m_虚线);
	for (uint32 i = 0; i < num; ++i) {
		//auto& rData = *DEF_引用插座数据(f_get输入插座(2), i);
		S_骨骼IK* IK = 骨骼包含的IK[i];

		IK->m_骨骼段数 = 0;
		if (!IK->m_末端) continue;

		IK->m_始端 = IK->m_末端;
		if (IK->m_深度) {
			for (uint32 i = 0; i < IK->m_深度; ++i) {

				if (IK->m_始端->m_父对象 && static_cast<S_物体*>(IK->m_始端->m_父对象)->m_Type == E_物体类型::t_骨骼) {
					IK->m_始端 = static_cast<S_物体*>(IK->m_始端->m_父对象);
					++IK->m_骨骼段数;
				}
				else {
					break;
				}
			}
		}
		else {
			for (;;) {

				if (IK->m_始端->m_父对象 && static_cast<S_物体*>(IK->m_始端->m_父对象)->m_Type == E_物体类型::t_骨骼) {
					IK->m_始端 = static_cast<S_物体*>(IK->m_始端->m_父对象);
					++IK->m_骨骼段数;
				}
				else {
					break;
				}
			}
		}
		骨架->m_IK[骨架->m_IK数量] = IK;
		++骨架->m_IK数量;



		if (IK->m_使用骨节坐标) {
			auto* 骨节 = f_ob_from骨骼(IK->m_末端)->m_骨节B;
		}
	}

	f_get输出插座(1)->f_setData(m_骨架);
	return false;
}


S_物体* C_骨架节点::f_虚拟体() {
	return nullptr;
}

void C_骨架节点::f_删除() {
	f_node_物体从主场景中移除(m_骨架);
	f_node_从全局容器移除物体(m_骨架);
}

void C_骨架节点::f_回收() {
	f_node_物体添加到主场景(m_骨架);
	f_node_物体添加到全局容器(m_骨架);
}

void C_骨架节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_11, S_引擎配置::g_文件版本号)) {
			//下一次读取数据指针 = f_ob_Load物体(m_骨架, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_骨架节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	
	f_ob_Save物体(m_骨架, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建骨骼节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_骨架节点(ctx);
}

C_节点基类* f_node_加载骨骼节点(S_设备环境& ctx, FILE* f) {
	C_骨架节点* node = new C_骨架节点(ctx);
	return node;
}

void f_node_保存骨骼节点(C_节点基类* n, FILE* f) {
	C_骨架节点* node = dynamic_cast<C_骨架节点*>(n);
}





C_骨骼IK节点::C_骨骼IK节点(S_设备环境& ctx) : C_节点基类(DEF_骨骼IK节点, E_节点类型::e_节点Type_约束) {
	f_setWName(u"IK");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Vec3插座_v1_I(u"控制点");
	DEF_创建IK插座_O(u"IK");

	DEF_Vec3插座数据(f_get输入插座(3)) = {};


	m_虚拟体 = f_node_创建虚拟体(m_Ctx);
	m_虚拟体->m_颜色 = { 0,0,0,255 };
	f_ob_set数据槽数量(m_虚拟体, 1);
	f_ob_set数据(m_虚拟体, f_surface_创建实例(S_节点数据::g_me_十字叉, true, true, true, false, true, true));
	f_ob_set材质(m_虚拟体, f_NodeCtx_get基本光照线段材质());
	f_ob_set线宽(m_虚拟体, 2.0, 0);
	f_ob_set颜色2(m_虚拟体, m_虚拟体->m_颜色, 0);
	f_mesh_set绘制内存属性(f_ob_getMesh(m_虚拟体, 0), {});
	f_mesh_计算包围盒(f_ob_getMesh(m_虚拟体, 0));

	auto 网格属性 = f_init_MeshTranform();
	f_mesh_set网格元素绘制属性(f_ob_getMesh(m_虚拟体, 0), 网格属性);

	f_node_物体添加到主场景(m_虚拟体);

	m_Value = f_ob_创建IK();


	m_迭代次数 = f_alloc_UI32Prop(nullptr, u"迭代次数", 12);
	m_迭代次数.m_私有 = true;

	m_节数 = f_alloc_UI32Prop(nullptr, u"节数", 0);
	m_节数.m_私有 = true;

	m_虚拟体类型 = f_alloc_EnumProp(nullptr, { {u"交叉轴",u""}, {u"反向轴",u""} ,{u"线框球",u""} }, u"虚拟体类型");
	m_虚拟体类型.m_私有 = true;

	m_使用骨节 = f_alloc_BoolProp(nullptr, u"使用骨节坐标");
	m_使用骨节.m_私有 = true;

}

C_骨骼IK节点::~C_骨骼IK节点() {
	f_ob_销毁(m_虚拟体);
	f_ob_销毁IK(m_Value);

	f_prop_Release(m_节数);
	f_prop_Release(m_迭代次数);
	f_prop_Release(m_使用骨节);
}

bool C_骨骼IK节点::f_update() {
	m_Value->m_深度 = f_prop_UI32(m_节数);
	m_Value->m_迭代次数 = f_prop_UI32(m_迭代次数);
		
	m_Value->m_末端坐标 = m_虚拟体;
	m_Value->m_使用骨节坐标 = f_prop_Bool(m_使用骨节);
		
	
	switch (f_prop_enum(m_虚拟体类型)) {
		case E_虚拟体类型::E_交叉轴:
			break;
		case E_虚拟体类型::E_方向轴:
			break;
		case E_虚拟体类型::E_线框球:
			break;
		default:
			break;
	}
	f_get输出插座(1)->f_setData(m_Value);
	return false;
}

S_物体* C_骨骼IK节点::f_虚拟体() {
	return m_虚拟体;
}

void C_骨骼IK节点::f_删除() {
	f_node_物体从主场景中移除(m_虚拟体);
}

void C_骨骼IK节点::f_回收() {
	f_node_物体添加到主场景(m_虚拟体);
}

void C_骨骼IK节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//下一次读取数据指针 = f_ob_Load物体(m_虚拟体, 下一次读取数据指针);

		下一次读取数据指针 = f_prop_Load(m_节数, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_迭代次数, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_骨骼IK节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_ob_Save物体(m_虚拟体, 块);

	f_prop_Save(m_节数, 块);
	f_prop_Save(m_迭代次数, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建骨骼IK节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_骨骼IK节点(ctx);
}

C_节点基类* f_node_加载骨骼IK节点(S_设备环境& ctx, FILE* f) {
	C_骨骼IK节点* node = new C_骨骼IK节点(ctx);
	return node;
}

void f_node_保存骨骼IK节点(C_节点基类* n, FILE* f) {
	C_骨骼IK节点* node = dynamic_cast<C_骨骼IK节点*>(n);
}





C_虚拟空物体节点::C_虚拟空物体节点(S_设备环境& ctx) : C_节点基类(DEF_骨骼IK节点, E_节点类型::e_节点Type_约束) {
	f_setWName(u"IK");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Vec3插座_v1_I(u"控制点");
	DEF_创建IK插座_O(u"IK");

	DEF_Vec3插座数据(f_get输入插座(3)) = {};


	m_虚拟体 = f_node_创建虚拟体(m_Ctx);
	m_虚拟体->m_颜色 = { 0,0,0,255 };
	f_ob_set数据槽数量(m_虚拟体, 1);
	f_ob_set数据(m_虚拟体, f_surface_创建实例(S_节点数据::g_me_十字叉, true, true, true, false, true, true));
	f_ob_set材质(m_虚拟体, f_NodeCtx_get基本光照线段材质());
	f_ob_set线宽(m_虚拟体, 2.0, 0);
	f_ob_set颜色2(m_虚拟体, m_虚拟体->m_颜色, 0);
	f_mesh_set绘制内存属性(f_ob_getMesh(m_虚拟体, 0), {});
	f_mesh_计算包围盒(f_ob_getMesh(m_虚拟体, 0));

	auto 网格属性 = f_init_MeshTranform();
	f_mesh_set网格元素绘制属性(f_ob_getMesh(m_虚拟体, 0), 网格属性);

	f_node_物体添加到主场景(m_虚拟体);

	m_虚拟体类型 = f_alloc_EnumProp(nullptr, { {u"交叉轴",u""}, {u"反向轴",u""} ,{u"线框球",u""} }, u"虚拟体类型");
	m_虚拟体类型.m_私有 = true;


}

C_虚拟空物体节点::~C_虚拟空物体节点() {
	f_ob_销毁(m_虚拟体);
	f_prop_Release(m_虚拟体类型);
}

bool C_虚拟空物体节点::f_update() {
	
	switch (f_prop_enum(m_虚拟体类型)) {
		case E_虚拟体类型::E_交叉轴:
			break;
		case E_虚拟体类型::E_方向轴:
			break;
		case E_虚拟体类型::E_线框球:
			break;
		default:
			break;
	}
	return false;
}

S_物体* C_虚拟空物体节点::f_虚拟体() {
	return m_虚拟体;
}

void C_虚拟空物体节点::f_删除() {
	f_node_物体从主场景中移除(m_虚拟体);
}

void C_虚拟空物体节点::f_回收() {
	f_node_物体添加到主场景(m_虚拟体);
}

void C_虚拟空物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//下一次读取数据指针 = f_ob_Load物体(m_虚拟体, 下一次读取数据指针);
		//下一次读取数据指针 = f_prop_Load(m_虚拟体类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_虚拟空物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_ob_Save物体(m_虚拟体, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建虚拟空物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_虚拟空物体节点(ctx);
}

C_节点基类* f_node_加载虚拟空物体节点(S_设备环境& ctx, FILE* f) {
	C_虚拟空物体节点* node = new C_虚拟空物体节点(ctx);
	return node;
}

void f_node_保存虚拟空物体节点(C_节点基类* n, FILE* f) {
	C_虚拟空物体节点* node = dynamic_cast<C_虚拟空物体节点*>(n);
}




C_物体绑定骨骼节点::C_物体绑定骨骼节点(S_设备环境& ctx) : C_节点基类("物体绑定骨骼节点", E_节点类型::e_节点Type_物体) {
	f_setWName(u"骨架");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_I(u"物体");
	DEF_创建骨架插座_I(u"骨架");
}

C_物体绑定骨骼节点::~C_物体绑定骨骼节点() {
}

bool C_物体绑定骨骼节点::f_update() {
	auto 物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto 骨架 = DEF_骨架插座数据(f_get输入插座(2), 0);

	if (骨架) {
		物体->m_骨架 = f_ob_from骨架(骨架);
	}

	return false;
}

C_节点基类* f_node_加载物体绑定骨骼节点(S_设备环境& ctx, FILE* f) {
	C_物体绑定骨骼节点* node = new C_物体绑定骨骼节点(ctx);
	return node;
}
void f_node_保存物体绑定骨骼节点(C_节点基类* n, FILE* f) {
	C_物体绑定骨骼节点* node = dynamic_cast<C_物体绑定骨骼节点*>(n);
}




C_摄像机节点::C_摄像机节点(S_设备环境& ctx) : C_节点基类(DEF_摄像机节点, E_节点类型::e_节点Type_摄像机) {
	f_setWName(u"摄像机");
	m_Ctx = ctx;

	m_Ob = f_node_创建虚拟体(ctx);
	m_Ob->m_Name = u"摄像机虚拟体";
	m_Ob->m_颜色 = { 2,2,2,255 };
	f_NodeCtx_录物体类节点(this, m_Ob);
	m_摄像机 = (S_摄像机*)f_ob_创建(m_Ctx, E_物体类型::t_摄像机);
	m_摄像机->m_Name = u"摄像机";
	f_ob_add子物体(m_Ob, m_摄像机);


	f_ob_set数据槽数量(m_Ob, 1);
	f_ob_set数据(m_Ob, f_surface_创建实例(S_节点数据::g_me_摄像机锥形, true, true, true, false, true, true), 0);
	f_ob_set材质(m_Ob, f_NodeCtx_get基本光照线段材质(), 0);
	f_ob_set颜色2(m_Ob, m_Ob->m_颜色, 0, 0);

	f_mesh_set绘制内存属性(f_ob_getMesh(m_Ob, 0), {});

	f_node_物体添加到全局容器(m_摄像机);
	f_node_物体添加到全局容器(m_Ob);
	f_node_物体添加到主场景(m_Ob);

	m_动画曲线列表 = f_an_创建曲线层();

	C_插座基类* socket;
	DEF_创建iVec2插座_Ip(u"分辨率", &m_摄像机->m_分辨率);
	DEF_创建F32插座_I(u"视野角度", &m_摄像机->m_视角);

	DEF_创建物体插座_O(u"摄像机");

}

C_摄像机节点::~C_摄像机节点() {
	f_node_从全局容器移除物体(m_摄像机);
	f_ob_销毁摄像机(m_摄像机);
	f_ob_销毁(m_Ob);
}

bool C_摄像机节点::f_update() {
	float32 视野角度 = DEF_F32插座数据(f_get输入插座(2));
	vec2 比例 = { float32(m_摄像机->m_分辨率.x), float32(m_摄像机->m_分辨率.y) };
	m_摄像机->f_set宽高比(比例);
	m_摄像机->f_set视角(视野角度);
	

	f_node_虚拟体_设置摄像机虚拟网格(m_Ob, nullptr, m_摄像机, {});
	auto mesh = f_ob_getMesh(m_Ob, 0);
	m_Ob->m_Bound = f_mesh_计算包围盒(mesh, nullptr);

	f_get输出插座(1)->f_setData(m_Ob);
	return false;
}

std::string C_摄像机节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";

	std::string name = f_getName();

	if (m_区域父节点) {
		m_区域父节点->m_Code;
		return "";
	}
	return m_Code;
}

S_动画曲线组* C_摄像机节点::f_getAN曲线() {
	f_an_清除曲线通道(m_动画曲线列表);

	if (m_Ob->m_位置) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_位置);
	}
	if (m_Ob->m_旋转) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_旋转);
	}
	if (m_Ob->m_缩放) {
		f_an_添加曲线通道(m_动画曲线列表, m_Ob->m_缩放);
	}
	return m_动画曲线列表;
}

S_物体* C_摄像机节点::f_虚拟体() {
	return m_Ob;
}

void C_摄像机节点::f_删除() {
	m_Ob->m_显示 = false;
	f_node_移除虚拟体(m_Ob);

}

void C_摄像机节点::f_回收() {
	m_Ob->m_显示 = true;
}

void C_摄像机节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_ob_Load物体(m_Ob, f);
}

void C_摄像机节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_ob_Save物体(m_Ob, f);
}
C_节点基类* f_node_创建摄像机节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_摄像机节点(ctx);
}

C_节点基类* f_node_加载摄像机节点(S_设备环境& ctx, FILE* f) {
	C_摄像机节点* node = new C_摄像机节点(ctx);
	return node;
}

void f_node_保存摄像机节点(C_节点基类* n, FILE* f) {
	C_摄像机节点* node = dynamic_cast<C_摄像机节点*>(n);
}





C_物体拷贝节点::C_物体拷贝节点(S_设备环境& ctx) : C_节点基类("物体拷贝节点", E_节点类型::e_节点Type_物体) {
	m_GPU环境 = ctx;
	m_Ctx = ctx;

	f_setWName(u"物体拷贝节点");

	m_当前拷贝物体根物体 = f_ob_创建(m_GPU环境, E_物体类型::t_包);
	m_当前拷贝物体根物体->m_Name = u"复制物体跟物体";

	f_NodeCtx_get默认场景()->f_add物体({ m_当前拷贝物体根物体 }, E_场景物体容器类型::e_集合);
	f_NodeCtx_录物体类节点(this);

	
	f_node_物体添加到主场景(m_当前拷贝物体根物体);
	f_node_物体添加到全局容器(m_当前拷贝物体根物体);


	C_插座基类* socket;

	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建UI32插座_I(u"数量");

	DEF_创建物体_1D插座_O(u"新物体");
	DEF_创建物体插座_O(u"父物体");

	m_是否实例 = f_alloc_BoolProp(nullptr, u"是否实例");
	m_是否实例.m_私有 = true;
	f_prop_Bool(m_是否实例) = true;

	DEF_UI32插座数据(f_get输入插座(2), 0) = 1;
}

C_物体拷贝节点::~C_物体拷贝节点() {
	f_prop_Release(m_是否实例);

	f_node_物体从主场景中移除(m_当前拷贝物体根物体);
	f_ob_销毁(m_当前拷贝物体根物体);
}

bool C_物体拷贝节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	if (socket1->m_有新数据 || socket2->m_有新数据 || 1) {
		auto* 输入物体组 = DEF_物体插座_1D数据(socket1, 0);
		uint32	数量 = DEF_UI32插座数据(socket2, 0);
		if(数量 >= -1) 数量 = 0;
		数量 = DEF_Max(数量, 1);


		auto* newObs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
		f_node_删除物体(newObs);

		auto* scene = f_NodeCtx_get默认场景();
		f_ob_清除子物体(m_当前拷贝物体根物体);
		

		f_NodeCtx_clear选中物体();
		f_NE_拷贝物体(输入物体组, 数量, m_当前拷贝物体根物体, newObs, false, m_Ctx);
		f_scene_更新物体渲染(f_NodeCtx_get默认场景(), m_当前拷贝物体根物体);

		f_get输出插座(2)->f_setData(m_当前拷贝物体根物体);
	}
	
	return false;
}

S_物体* C_物体拷贝节点::f_虚拟体() {
	return m_当前拷贝物体根物体;
}

void C_物体拷贝节点::f_删除() {
	f_NodeCtx_get默认场景()->f_remove物体(m_当前拷贝物体根物体, E_场景物体容器类型::e_集合);
	f_node_从全局容器移除物体(m_当前拷贝物体根物体);
}

void C_物体拷贝节点::f_回收() {
	f_NodeCtx_get默认场景()->f_add物体({ m_当前拷贝物体根物体 }, E_场景物体容器类型::e_集合);
	f_node_物体添加到全局容器(m_当前拷贝物体根物体);
}

void C_物体拷贝节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_是否实例, f);
}

void C_物体拷贝节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_是否实例, f);
}

C_节点基类* f_node_创建物体拷贝节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体拷贝节点(ctx);
}

C_节点基类* f_node_加载物体拷贝节点(S_设备环境& ctx, FILE* f) {
	C_物体拷贝节点* node = new C_物体拷贝节点(ctx);
	return node;
}

void f_node_保存物体拷贝节点(C_节点基类* n, FILE* f) {
	C_物体拷贝节点* node = dynamic_cast<C_物体拷贝节点*>(n);
}






C_创建物体实例节点::C_创建物体实例节点(S_设备环境& ctx) : C_节点基类(DEF_创建物体实例节点, E_节点类型::e_节点Type_物体) {
	m_GPU环境 = ctx;
	m_Ctx = ctx;
	f_setWName(u"创建实例");

	f_NodeCtx_录物体类节点(this);
	DEF_创建物体插座_I(u"物体");
	DEF_创建UI32插座_I(u"数量");

	DEF_创建物体_1D插座_O(u"新物体");


	DEF_UI32插座数据(f_get输入插座(2), 0) = 1;


	m_实例方式 = f_alloc_EnumProp(nullptr, {{u"父物体"}, {u"子物体"}}, u"实例方式");
	m_实例方式.m_私有 = true;

	m_开启实例材质 = f_alloc_BoolProp(nullptr, u"实例材质");
	m_开启实例材质.m_私有 = true;
}

C_创建物体实例节点::~C_创建物体实例节点() {
	f_prop_Release(m_实例方式);
}

bool C_创建物体实例节点::f_update() {
	auto* socket2 = f_get输入插座(2);
	uint32	数量 = DEF_UI32插座数据(socket2, 0);
	auto* newObs = DEF_物体插座_1D数据(f_get输出插座(1), 0);

	switch (f_prop_enum(m_实例方式)) {
		case 0: {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Object_1D);
			auto* socket1 = f_get输入插座(1);
			
			auto* 输入物体 = DEF_物体插座_1D数据(socket1);

			for (uint32 i = 0; i < 输入物体->count; ++i) {
				f_ob_清除子物体(输入物体->ptr_userData[i]);
				f_ob_fill实例(输入物体->ptr_userData[i], 数量);

				for (uint32 k = 0; k < 数量; ++k) {
					f_ob_set颜色2(输入物体->ptr_userData[i], 输入物体->ptr_userData[i]->m_颜色, k, E_物体网格元素类型::e_MT_焦点);
					f_ob_set颜色2(输入物体->ptr_userData[i], 输入物体->ptr_userData[i]->m_颜色, k, E_物体网格元素类型::e_MT_面);
					f_ob_set颜色2(输入物体->ptr_userData[i], 输入物体->ptr_userData[i]->m_颜色, k, E_物体网格元素类型::e_MT_边);
					f_ob_set颜色2(输入物体->ptr_userData[i], 输入物体->ptr_userData[i]->m_颜色, k, E_物体网格元素类型::e_MT_框);
				}
			}

			f_get输出插座(1)->f_setData(输入物体);
			break;
		}
		case 1: {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Object);
			auto* socket1 = f_get输入插座(1);
			auto* socket2 = f_get输入插座(2);

			if (socket1->m_有新数据 || socket2->m_有新数据 || 1) {
				auto* 输入物体 = DEF_物体插座数据(socket1);
				auto* 实例物体 = DEF_物体插座_1D数据(f_get输出插座(1));
				uint32	数量 = DEF_UI32插座数据(socket2, 0);
				if (数量 >= -1) 数量 = 0;
				数量 = DEF_Max(数量, 1);


				
				f_node_删除物体(newObs);

				f_NodeCtx_clear选中物体();
				f_ob_清除子物体(输入物体);

				f_ob_fill实例(输入物体, 数量);
				f_core_array_resize((S_Array*)实例物体, 数量);
				
				for (uint32 i = 0; i < 数量; ++i) {
					实例物体->ptr_userData[i] = f_ob_get子对象(输入物体, i);
				}
			}
			break;
		}
		default:
			break;
	}

	if (f_prop_Bool(m_开启实例材质)) {
		for (uint32 i = 0; i < newObs->count; ++i) {
			newObs->ptr_userData[i]->m_实例材质ID.resize(数量);
		}
	}
	else {
		for (uint32 i = 0; i < newObs->count; ++i) {
			newObs->ptr_userData[i]->m_实例材质ID.resize(0);
		}
	}
	
	return false;
}

S_物体* C_创建物体实例节点::f_虚拟体() {
	return nullptr;
}

void C_创建物体实例节点::f_删除() {
}

void C_创建物体实例节点::f_回收() {
}

void C_创建物体实例节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_实例方式, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_开启实例材质, 下一次读取数据指针);
	}

	free(文件块.m_data);
}

void C_创建物体实例节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_实例方式, 块);
	f_prop_Save(m_开启实例材质, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建创建物体实例节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_创建物体实例节点(ctx);
}

C_节点基类* f_node_加载创建物体实例节点(S_设备环境& ctx, FILE* f) {
	C_创建物体实例节点* node = new C_创建物体实例节点(ctx);
	return node;
}

void f_node_保存创建物体实例节点(C_节点基类* n, FILE* f) {
	C_创建物体实例节点* node = dynamic_cast<C_创建物体实例节点*>(n);
}






C_设置物体矩阵节点::C_设置物体矩阵节点(S_设备环境& ctx) : C_节点基类("设置物体矩阵节点") {
	f_setWName(u"设置物体矩阵节点");
	m_Ctx = ctx;

	C_插座基类* socket;

	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建Mat4X4_1D插座_I(u"矩阵");

	DEF_创建物体_1D插座_O(u"物体");


	m_设置方式 = f_alloc_EnumProp(nullptr, {
		{u"物体"},
		{u"实例"},
	}, u"设置方式");
	m_设置方式.m_私有 = true;

}

C_设置物体矩阵节点::~C_设置物体矩阵节点() {
	f_prop_Release(m_设置方式);
}

bool C_设置物体矩阵节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	if(socket1->f_isLink() == false) return false; 

	auto* objs = DEF_物体插座_1D数据(f_get输入插座(1), 0);
	auto* mats = DEF_Mat44插座_1D数据(f_get输入插座(2), 0);

	uint32 num = objs->count;
	
	switch (f_prop_enum(m_设置方式)) {
		case 0: {
			bool 矩阵多例 = mats->count >= num;
			for (uint32 i = 0; i < num; ++i) {
				if (!objs->ptr_userData[i]) continue;
				f_ob_set矩阵(objs->ptr_userData[i], 矩阵多例 ? mats->ptr_userData[i] : mats->ptr_userData[0], objs->ptr_userData[i]->m_实例ID);
			}
			break;
		}
		case 1: {
			for (uint32 i = 0; i < num; ++i) {
				if(!objs->ptr_userData[i]) continue;

				auto* ob = objs->ptr_userData[i];
				uint32 物体实例数量 = ob->m_变换矩阵.m_Mem.m_数量;
				auto* 物体变换矩阵 = f_buf_Mat44_ptr(ob->m_变换矩阵);

				bool 矩阵多例 = mats->count >= 物体实例数量;
				for (uint32 k = 0; k < 物体实例数量; ++k) {
					物体变换矩阵[k] = 矩阵多例 ? mats->ptr_userData[k] : mats->ptr_userData[0];

				}
			}
			break;
		}
		default:
			break;
	}
	f_get输出插座(1)->f_setData(objs);
	return false;
}

void C_设置物体矩阵节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_设置方式, 下一次读取数据指针);
	}

	free(文件块.m_data);
}

void C_设置物体矩阵节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_设置方式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建设置物体矩阵节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体矩阵节点(ctx);
}

C_节点基类* f_node_加载设置物体矩阵节点(S_设备环境& ctx, FILE* f) {
	C_设置物体矩阵节点* node = new C_设置物体矩阵节点(ctx);
	return node;
}

void f_node_保存设置物体矩阵节点(C_节点基类* n, FILE* f) {
	C_设置物体矩阵节点* node = dynamic_cast<C_设置物体矩阵节点*>(n);
}



C_取物体矩阵节点::C_取物体矩阵节点(S_设备环境 & ctx) : C_节点基类(DEF_取物体矩阵节点) {
	f_setWName(u"取矩阵");
	m_Ctx = ctx;

	C_插座基类* socket;

	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建Mat4X4_1D插座_O(u"矩阵");
}
C_取物体矩阵节点::~C_取物体矩阵节点() {

}
bool C_取物体矩阵节点::f_update() {
	auto* socket1 = f_get输入插座(1);

	auto* 矩阵 = DEF_Mat44插座_1D数据(f_get输出插座(1), 0);
	if (socket1->f_isLink()) {
		auto* 物体 = DEF_物体插座_1D数据(f_get输入插座(1), 0);
		
		f_core_array_resize((S_Array*)矩阵, 物体->count);
		for (uint32 i = 0; i < 物体->count; ++i) {
			矩阵->ptr_userData[i] = f_ob_get变换矩阵(物体->ptr_userData[i], 物体->ptr_userData[i]->m_实例ID);
		}
	}
	else {
		f_core_array_resize((S_Array*)矩阵, 0);
	}
	
	return false;
}

void C_取物体矩阵节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//下一次读取数据指针 = f_prop_Load(m_是否改变原数据, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_取物体矩阵节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_prop_Save(m_是否改变原数据, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建取物体矩阵节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_取物体矩阵节点(ctx);
}
C_节点基类* f_node_加载取物体矩阵节点(S_设备环境& ctx, FILE* f) {
	C_取物体矩阵节点* node = new C_取物体矩阵节点(ctx);
	return node;
}
void f_node_保存取物体矩阵节点(C_节点基类* n, FILE* f) {
	C_取物体矩阵节点* node = dynamic_cast<C_取物体矩阵节点*>(n);
}




C_设置物体变换节点::C_设置物体变换节点(S_设备环境& ctx) : C_节点基类(DEF_设置物体变换节点) {
	f_setWName(u"设置物体变换节点");
	m_Ctx = ctx;

	C_插座基类* socket;

	DEF_创建物体_1D插座_I(u"物体");
	//DEF_创建引用插座_I(u"网格物体");

	DEF_创建Vec3_1D插座_I(u"移动");
	DEF_创建Vec3_1D插座_I(u"旋转");
	DEF_创建Vec3_1D插座_I(u"缩放");

	DEF_创建物体_1D插座_O(u"引用物体");


	auto& l = *DEF_Vec3插座_1D数据(f_get输入插座(2));
	auto& r = *DEF_Vec3插座_1D数据(f_get输入插座(3));
	auto& s = *DEF_Vec3插座_1D数据(f_get输入插座(4));
	l.ptr_userData[0] = {0,0,0};
	r.ptr_userData[0] = {0,0,0};
	s.ptr_userData[0] = {1,1,1};


	m_变换方式 = f_alloc_EnumProp(nullptr, {
		//{u"手动"},
		{u"直接"},
		{u"增量加"},
		{u"增量减"},
		{u"中心"},
	}, u"变换方式");
	m_变换方式.m_私有 = true;

	m_物体模式 = f_alloc_EnumProp(nullptr, {
		{u"物体"},
		{u"实例"},
		}, u"物体模式");
	m_物体模式.m_私有 = true;
}

C_设置物体变换节点::~C_设置物体变换节点() {
	f_prop_Release(m_变换方式);
	f_prop_Release(m_物体模式);
}

bool C_设置物体变换节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	S_OBArray* in物体数据1 = DEF_物体插座_1D数据(f_get输入插座(1), 0);
	
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);
	auto* socket4 = f_get输入插座(4);
	const auto& 移动 = *DEF_Vec3插座_1D数据(socket2);
	const auto& 旋转 = *DEF_Vec3插座_1D数据(socket3);
	const auto& 缩放 = *DEF_Vec3插座_1D数据(socket4);


	uint32 num = in物体数据1->count;
	if (socket1->f_isLink() && num) {
		
		auto* ob = in物体数据1->ptr_userData;


		switch (f_prop_enum(m_物体模式)) {
			case 0: {
				bool 移动单例 = 移动.count < num;
				bool 旋转单例 = 旋转.count < num;
				bool 缩放单例 = 缩放.count < num;

				switch (f_prop_enum(m_变换方式)) {
					case 0: {
						for (uint32 i = 0; i < num; ++i) {
							f_物体变换(ob[i], 移动.ptr_userData[移动单例 ? 0 : i], 旋转.ptr_userData[旋转单例 ? 0 : i], 缩放.ptr_userData[缩放单例 ? 0 : i], 0);
						}
						break;
					}
					case 1: {
						for (uint32 i = 0; i < num; ++i) {
							ob[i]->f_set位置(ob[i]->m_变换.position + 移动.ptr_userData[移动单例 ? 0 : i], i);
							ob[i]->f_set旋转(ob[i]->m_变换.rotation + 旋转.ptr_userData[旋转单例 ? 0 : i], i);
							ob[i]->f_set缩放(ob[i]->m_变换.scale + 缩放.ptr_userData[缩放单例 ? 0 : i], i);
						}
						break;
					}
					case 2: {
						for (uint32 i = 0; i < num; ++i) {
							ob[i]->f_set位置(ob[i]->m_变换.position - 移动.ptr_userData[移动单例 ? 0 : i], i);
							ob[i]->f_set旋转(ob[i]->m_变换.rotation - 旋转.ptr_userData[旋转单例 ? 0 : i], i);
							ob[i]->f_set缩放(ob[i]->m_变换.scale - 缩放.ptr_userData[缩放单例 ? 0 : i], i);
						}
						break;
					}
					default:
						break;
				}
				break;
			}
			case 1: {
				for (uint32 i = 0; i < num; ++i) {
					uint32 实例数量 = f_ob_get实例数量(ob[i]);

					bool 移动单例 = 移动.count < 实例数量;
					bool 旋转单例 = 旋转.count < 实例数量;
					bool 缩放单例 = 缩放.count < 实例数量;

					for (uint32 k = 0; k < 实例数量; ++k) {
						auto so = f_ob_get子对象(ob[i], k);
						if(!so) continue;

						switch (f_prop_enum(m_变换方式)) {
							case 0: {
								f_ob_setLoc(so, 移动.ptr_userData[移动单例 ? 0 : k]);
								f_ob_setRot(so, 旋转.ptr_userData[旋转单例 ? 0 : k]);
								f_ob_setScale(so, 缩放.ptr_userData[缩放单例 ? 0 : k]);
								break;
							}
							case 1: {
								f_ob_setLoc(so, so->m_变换.position + 移动.ptr_userData[移动单例 ? 0 : k], k);
								f_ob_setRot(so, so->m_变换.rotation + 旋转.ptr_userData[旋转单例 ? 0 : k], k);
								f_ob_setScale(so, so->m_变换.scale + 缩放.ptr_userData[缩放单例 ? 0 : k], k);
								break;
							}
							case 2: {
								f_ob_setLoc(so, so->m_变换.position - 移动.ptr_userData[移动单例 ? 0 : k], k);
								f_ob_setRot(so, so->m_变换.rotation - 旋转.ptr_userData[旋转单例 ? 0 : k], k);
								f_ob_setScale(so, so->m_变换.scale - 缩放.ptr_userData[缩放单例 ? 0 : k], k);
								break;
							}
							default:
								break;
						}
					}
				}
				break;
			}
			default:
				break;
		}

		switch (f_prop_enum(m_变换方式)) {
			case 0: {
				
				break;
			}
			case 2: {
				
				break;
			}
		}
		
		
		f_get输出插座(1)->f_setData(in物体数据1);
	}
	else {
		
		f_get输出插座(1)->f_setData((void*)nullptr);
	}
	
	return false;
}

void C_设置物体变换节点::f_物体变换(S_物体* ob, const vec3& loc, const vec3& rot, const vec3& scal, uint32 offset) {
	ob->f_set位置(loc, offset);
	ob->f_set旋转(rot, offset);
	ob->f_set缩放(scal, offset);
}

void C_设置物体变换节点::f_读取(FILE * f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_变换方式, 下一次读取数据指针);
		}
		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_21, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_物体模式, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_设置物体变换节点::f_写入(FILE * f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_变换方式, 块);
	f_prop_Save(m_物体模式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建设置物体变换节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体变换节点(ctx);
}

C_节点基类* f_node_加载设置物体变换节点(S_设备环境& ctx, FILE* f) {
	C_设置物体变换节点* node = new C_设置物体变换节点(ctx);
	return node;
}

void f_node_保存设置物体变换节点(C_节点基类* n, FILE* f) {
	C_物体拷贝节点* node = dynamic_cast<C_物体拷贝节点*>(n);
}






C_取物体变换节点::C_取物体变换节点(S_设备环境& ctx) : C_节点基类(DEF_取物体变换节点, E_节点类型::e_节点Type_计算) {
	f_setWName(u"取物体变换");
	m_Ctx = ctx;


	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建Vec3_1D插座_O(u"移动", nullptr);
	DEF_创建Vec3_1D插座_O(u"旋转", nullptr);
	DEF_创建Vec3_1D插座_O(u"缩放", nullptr);

	m_开启缓存节点 = true;
	m_数据是否以缓存 = false;
}

C_取物体变换节点::~C_取物体变换节点() {
}

bool C_取物体变换节点::f_update() {
	auto* socket = f_get输入插座(1);
	if(m_数据是否以缓存 && m_缓存节点) return false;
	

	auto* x = DEF_Vec3插座_1D数据(f_get输出插座(1), 0);
	auto* y = DEF_Vec3插座_1D数据(f_get输出插座(2), 0);
	auto* z = DEF_Vec3插座_1D数据(f_get输出插座(3), 0);

	auto* 物体 = DEF_物体插座_1D数据(f_get输入插座(1), 0);


	if (socket->f_isLink()) {
		f_core_array_resize((S_Array*)x, 物体->count);
		f_core_array_resize((S_Array*)y, 物体->count);
		f_core_array_resize((S_Array*)z, 物体->count);

		for (uint32 i = 0; i < 物体->count; ++i) {
			x->ptr_userData[i] = 物体->ptr_userData[i]->m_变换.position;
			y->ptr_userData[i] = 物体->ptr_userData[i]->m_变换.rotation;
			z->ptr_userData[i] = 物体->ptr_userData[i]->m_变换.scale;
		}
	}
	else {
		f_core_array_resize((S_Array*)x, 1);
		f_core_array_resize((S_Array*)y, 1);
		f_core_array_resize((S_Array*)z, 1);

		x->ptr_userData[0] = {};
		y->ptr_userData[0] = {};
		z->ptr_userData[0] = { 1,1,1 };
	}

	if (m_缓存节点) {
		m_数据是否以缓存 = true;
	}
	else {
		m_数据是否以缓存 = false;
	}

	return false;
}

void C_取物体变换节点::f_释放缓存() {
	m_数据是否以缓存 = false;
}

void C_取物体变换节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
			if (m_缓存节点) {
				auto* x = DEF_Vec3插座_1D数据(f_get输出插座(1), 0);
				auto* y = DEF_Vec3插座_1D数据(f_get输出插座(2), 0);
				auto* z = DEF_Vec3插座_1D数据(f_get输出插座(3), 0);

				下一次读取数据指针 = f_core_array_解((S_Array*)x, 下一次读取数据指针);
				下一次读取数据指针 = f_core_array_解((S_Array*)y, 下一次读取数据指针);
				下一次读取数据指针 = f_core_array_解((S_Array*)z, 下一次读取数据指针);

				m_数据是否以缓存 = true;
			}
		}
		else if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_4, S_引擎配置::g_文件版本号)) {
			//下一次读取数据指针 = f_prop_Load(m_外部加载, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_取物体变换节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	if (m_缓存节点) {
		auto* x = DEF_Vec3插座_1D数据(f_get输出插座(1), 0);
		auto* y = DEF_Vec3插座_1D数据(f_get输出插座(2), 0);
		auto* z = DEF_Vec3插座_1D数据(f_get输出插座(3), 0);

		f_core_array_包((S_Array*)x, 块);
		f_core_array_包((S_Array*)y, 块);
		f_core_array_包((S_Array*)z, 块);
	}

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建取物体变换节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_取物体变换节点(ctx);
}

C_节点基类* f_node_加载取物体变换节点(S_设备环境& ctx, FILE* f) {
	C_取物体变换节点* node = new C_取物体变换节点(ctx);
	return node;
}

void f_node_保存取物体变换节点(C_节点基类* n, FILE* f) {
	C_取物体变换节点* node = dynamic_cast<C_取物体变换节点*>(n);
}



C_设置物体绕轴旋转节点::C_设置物体绕轴旋转节点(S_设备环境& ctx) : C_节点基类(DEF_设置物体绕轴旋转节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"物体绕轴旋转");
	m_Ctx = ctx;

	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建Vec3_1D插座_I(u"轴向");
	DEF_创建F32_1D插座_I(u"角度");
	DEF_创建Vec3插座_v1_I(u"中心");

	DEF_创建物体_1D插座_O(u"物体");


	m_中心类型 = f_alloc_EnumProp(nullptr, {
		{u"自定义"},
		{u"物体中心"},
		//{u"增量减"},
							  }, u"中心类型");
	m_中心类型.m_私有 = true;
	f_prop_enum(m_中心类型) = 1;

}

C_设置物体绕轴旋转节点::~C_设置物体绕轴旋转节点() {
	f_prop_Release(m_中心类型);
}

bool C_设置物体绕轴旋转节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);
	auto* 物体 = DEF_物体插座_1D数据(socket1);
	auto* 轴向 = DEF_Vec3插座_1D数据(socket2);
	auto* 角度 = DEF_F32插座_1D数据(socket3);

	bool 轴向多例 = 轴向->count >= 物体->count;
	bool 角度多例 = 角度->count >= 物体->count;


	if (socket1->f_isLink() == false) {
		f_get输出插座(1)->f_setData((void*)nullptr);
		return false;
	}

	std::vector<vec3> 物体全局坐标(物体->count);
	vec3 中心 = {};
	switch (f_prop_enum(m_中心类型))
	{
		case 0: {
			中心 = DEF_Vec3插座数据(f_get输入插座(4));
			break;
		}
		default: {
			for (int32 i = 0; i < 物体->count; ++i) {
				auto* ob = 物体->ptr_userData[i];
				物体全局坐标[i] = ob->f_get位置();
				中心 += 物体全局坐标[i];
			}
			中心 /= 物体->count;
			break;
		}
	}
	

	for (int32 i = 0; i < 物体->count; ++i) {
		auto* ob = 物体->ptr_userData[i];

		vec3 局部位置 = ob->f_get位置();

		vec3 lr = ob->f_get旋转();
		vec4 lq = f_graph_欧拉角转四元数(lr);

		Mat44f 父对象逆矩阵 = f_mat44_Invert(f_ob_get父对象变换矩阵(ob, 0, false));
		父对象逆矩阵.m30 = 0;
		父对象逆矩阵.m31 = 0;
		父对象逆矩阵.m32 = 0;
		父对象逆矩阵.m33 = 1;

		Mat44f 父对象矩阵 = f_ob_get父对象变换矩阵(ob, 0, true);
		父对象矩阵.m30 = 0;
		父对象矩阵.m31 = 0;
		父对象矩阵.m32 = 0;
		父对象矩阵.m33 = 1;


		vec3 axial = 轴向多例 ? 轴向->ptr_userData[i] : 轴向->ptr_userData[0];
		float32 radin = 角度多例 ? 角度->ptr_userData[i] : 角度->ptr_userData[0];
		radin = M_角度转弧度(radin);
		 
		vec4 rot_q = f_graph_从轴向角度计算四元数(axial, radin);
		vec3 移动矢量 = (f_graph_quat变换坐标(rot_q, 物体全局坐标[i] - 中心));

		ob->f_set位置(局部位置 + ((中心 + 移动矢量) - 物体全局坐标[i]));

		vec3 视线向量 = axial;
		vec4 qa = f_graph_从轴向角度计算四元数(视线向量, (-(radin)));
		vec4 newQuat = f_graph_quat相乘(lq, qa);

		ob->f_set旋转(f_graph_四元数转欧拉角(newQuat));
	}
	f_get输出插座(1)->f_setData(物体);

	return false;
}

void C_设置物体绕轴旋转节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_中心类型, 下一次读取数据指针);
		}
		else if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_4, S_引擎配置::g_文件版本号)) {
			
		}
	}
	free(文件块.m_data);
}

void C_设置物体绕轴旋转节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_中心类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建设置物体绕轴旋转节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体绕轴旋转节点(ctx);
}

C_节点基类* f_node_加载设置物体绕轴旋转节点(S_设备环境& ctx, FILE* f) {
	C_设置物体绕轴旋转节点* node = new C_设置物体绕轴旋转节点(ctx);
	return node;
}

void f_node_保存设置物体绕轴旋转节点(C_节点基类* n, FILE* f) {
	C_设置物体绕轴旋转节点* node = dynamic_cast<C_设置物体绕轴旋转节点*>(n);
}



C_设置物体缩放节点::C_设置物体缩放节点(S_设备环境& ctx) : C_节点基类(DEF_设置物体缩放节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"设置物体缩放");
	m_Ctx = ctx;

	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建Vec3_1D插座_I(u"缩放");
	DEF_创建Vec3插座_v1_I(u"中心");

	DEF_创建物体_1D插座_O(u"物体");

	m_中心类型 = f_alloc_EnumProp(nullptr, {
			{u"自定义"},
			{u"物体中心"},
			//{u"增量减"},
							  }, u"中心类型");
	m_中心类型.m_私有 = true;
	f_prop_enum(m_中心类型) = 1;
}

C_设置物体缩放节点::~C_设置物体缩放节点() {
	f_prop_Release(m_中心类型);
}

bool C_设置物体缩放节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);



	if (socket1->m_有新数据) {
		
	}

	auto* 物体 = DEF_物体插座_1D数据(socket1);
	auto* 缩放 = DEF_Vec3插座_1D数据(socket2);

	bool 缩放多例 = 缩放->count >= 物体->count;

	if (socket1->f_isLink() == false) {
		f_get输出插座(1)->f_setData((void*)nullptr);
		return false;
	}

	std::vector<vec3> 物体全局坐标(物体->count);
	vec3 中心 = {};
	switch (f_prop_enum(m_中心类型)) {
		case 0: {
			中心 = DEF_Vec3插座数据(f_get输入插座(3));
			break;
		}
		default: {
			for (int32 i = 0; i < 物体->count; ++i) {
				auto* ob = 物体->ptr_userData[i];
				物体全局坐标[i] = ob->f_get位置();
				中心 += 物体全局坐标[i];
			}
			中心 /= 物体->count;
			break;
		}
	}


	for (int32 i = 0; i < 物体->count; ++i) {
		auto* ob = 物体->ptr_userData[i];

		vec3 位置 = ob->f_get位置();
		vec3 大小 = ob->f_get缩放();

		vec3 dir = 位置 - 中心;
		vec3 s = 缩放多例 ? 缩放->ptr_userData[i] : 缩放->ptr_userData[0];

		ob->f_set位置(中心 + dir * s);
		ob->f_set缩放(大小 * s);
	}

	f_get输出插座(1)->f_setData(物体);
	return false;
}

void C_设置物体缩放节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_中心类型, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_设置物体缩放节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_中心类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建设置物体缩放节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体缩放节点(ctx);
}

C_节点基类* f_node_加载设置物体缩放节点(S_设备环境& ctx, FILE* f) {
	C_设置物体缩放节点* node = new C_设置物体缩放节点(ctx);
	return node;
}

void f_node_保存设置物体缩放节点(C_节点基类* n, FILE* f) {
	C_设置物体缩放节点* node = dynamic_cast<C_设置物体缩放节点*>(n);
}




C_物体变换节点::C_物体变换节点(S_设备环境& ctx) : C_节点基类(DEF_物体变换节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"物体绕轴旋转");
	m_Ctx = ctx;

	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建物体_1D插座_O(u"物体");

	m_中心类型 = f_alloc_EnumProp(nullptr, {
		{u"自定义"},
		{u"物体中心"},
		//{u"增量减"},
							  }, u"中心类型");
	m_中心类型.m_私有 = true;
	f_prop_enum(m_中心类型) = 1;
}

C_物体变换节点::~C_物体变换节点() {
	f_prop_Release(m_中心类型);
}

bool C_物体变换节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* outSocket3 = f_get输出插座(3);
	auto* 物体 = DEF_物体插座_1D数据(socket1);

	for (int32 i = 0; i < 物体->count; ++i) {
		auto* ob = 物体->ptr_userData[i];

		vec3 位置 = ob->f_get位置();
		vec3 大小 = ob->f_get缩放();

	}

	f_get输出插座(3)->f_setData(物体);
	return false;
}

void C_物体变换节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_9, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_中心类型, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_物体变换节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_中心类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建物体变换节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体变换节点(ctx);
}

C_节点基类* f_node_加载物体变换节点(S_设备环境& ctx, FILE* f) {
	C_物体变换节点* node = new C_物体变换节点(ctx);
	return node;
}

void f_node_保存物体变换节点(C_节点基类* n, FILE* f) {
	C_物体变换节点* node = dynamic_cast<C_物体变换节点*>(n);
}






C_设置摄像机属性节点::C_设置摄像机属性节点(S_设备环境 & ctx) : C_节点基类(DEF_设置摄像机属性节点) {
	f_setWName(u"设置摄像机");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体插座_I(u"摄像机");
	DEF_创建Vec3插座_I(u"视点", nullptr);
	DEF_创建Vec3插座_I(u"旋转", nullptr);
	DEF_创建F32插座_I(u"视点距离", nullptr);
	DEF_创建F32插座_I(u"视野", nullptr);

	DEF_创建物体插座_O(u"摄像机");

	DEF_F32插座数据(f_get输入插座(4)) = -5;
	DEF_F32插座数据(f_get输入插座(5)) = 45;
}

C_设置摄像机属性节点::~C_设置摄像机属性节点() {
	
}

bool C_设置摄像机属性节点::f_update() {
	auto* 摄像机 = DEF_物体插座数据(f_get输入插座(1), 0);

	if (摄像机 && 摄像机->m_Type == E_物体类型::t_摄像机) {
		S_摄像机* camera = (S_摄像机*)摄像机;

		auto* socket2 = f_get输入插座(2);
		auto* socket3 = f_get输入插座(3);

		camera->m_视点 = DEF_Vec3插座数据(socket2);
		camera->m_变换.rotation = DEF_Vec3插座数据(socket3);
		camera->f_set视点偏移({});
		
		camera->m_视距 = DEF_F32插座数据(f_get输入插座(4));
		camera->m_视角 = DEF_F32插座数据(f_get输入插座(5));
		camera->m_isUpdate = true;
	}
	else {
		摄像机 = nullptr;
	}
	f_get输出插座(1)->f_setData(摄像机);
	return false;
}

void C_设置摄像机属性节点::f_读取(FILE * f) {
	C_节点基类::f_读取(f);
}

void C_设置摄像机属性节点::f_写入(FILE * f) {
	C_节点基类::f_写入(f);
}

C_节点基类* f_node_创建设置摄像机属性节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置摄像机属性节点(ctx);
}

C_节点基类* f_node_加载设置摄像机属性节点(S_设备环境& ctx, FILE* f) {
	C_设置摄像机属性节点* node = new C_设置摄像机属性节点(ctx);
	return node;
}

void f_node_保存设置摄像机属性节点(C_节点基类* n, FILE* f) {
	C_设置摄像机属性节点* node = dynamic_cast<C_设置摄像机属性节点*>(n);
}





static void f_转换blender的动画移动轴向(S_动画曲线组* 通道) {
	uint32 t = 0;
	
}

static void f_转换blender的动画旋转轴向(S_动画曲线组* 通道) {
	uint32 t = 0;
	
}

static void f_转换blender的动画交换轴向(S_动画曲线组* 通道) {
	f_core_list_moveItem(通道->曲线通道, 1, 2);
}

static void f_转换blender的动画轴向缩放(S_动画曲线组* 通道) {
	uint32 t = 0;
	
}

static void f_转换blender关键帧(S_动画曲线组* 通道) {
	uint32 t = 0;
	
}

static void f_递归所有物体(S_物体* ob) {
	if (ob->m_Type == E_物体类型::t_骨骼) {
		vec3 loc = {};
		if (ob->m_位置) {
			//ob->m_变换.location = f_an_曲线值(ob->m_位置, 0);
		}
		vec3 rot = {};
		if (ob->m_旋转) {
			//ob->m_变换.rotation = f_an_曲线值(ob->m_旋转, 0);
		}
		vec3 scale = { 1,1,1 };
		if (ob->m_缩放) {
			//ob->m_变换.scale = f_an_曲线值(ob->m_缩放, 0);
		}
	}
	//if (物体->m_缩放) f_转换blender的动画轴向(物体->m_缩放);
	for (auto& e : ob->m_子物体) {
		f_递归所有物体(static_cast<S_物体*>(e));
	}
}




C_外部加载物体节点::C_外部加载物体节点(S_设备环境& ctx) : C_节点基类(DEF_外部加载物体节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"外部物体");
	m_Ctx = ctx;


	C_插座基类* socket;
	DEF_创建物体_1D插座_O(u"物体");

	m_是否递归目录 = f_alloc_BoolProp(nullptr, u"递归目录");
	m_是否递归目录.m_私有 = true;
	f_prop_Bool(m_是否递归目录) = false;

	m_是否序列 = f_alloc_BoolProp(nullptr, u"序列");
	m_是否序列.m_私有 = true;
	f_prop_Bool(m_是否序列) = false;

	m_Path = f_alloc_PathProp(nullptr, u"文件路径");
	m_Path.m_私有 = true;

	m_文件类型 = f_alloc_EnumProp(nullptr, { {u"FBX", u""}, {u"OBJ", u""} }, u"文件类型", 0);
	m_文件类型.m_私有 = true;

	m_瓦片 = f_alloc_EnumProp(nullptr, { {u"XY", u""}, {u"XZ", u""} }, u"瓦片", 1);
	m_瓦片.m_私有 = true;

	m_网格类型 = f_alloc_EnumProp(nullptr, { {u"多边形", u""}, {u"网格", u""} }, u"面类型", 1);
	m_网格类型.m_私有 = true;
	
	m_预缩放 = f_alloc_F32Prop(nullptr, u"预缩放", 1.0);
	m_预缩放.m_私有 = true;

	m_平滑法线 = f_alloc_BoolProp(nullptr, u"平滑法线", true);
	m_平滑法线.m_私有 = true;


	m_重写加载 = true;

	m_应用变换 = f_alloc_BoolProp(nullptr, u"应用变换");
	m_应用变换.m_私有 = true;
	f_prop_Bool(m_应用变换) = false;

}

C_外部加载物体节点::~C_外部加载物体节点() {
	f_prop_Release(m_是否递归目录);
	f_prop_Release(m_是否序列);
	f_prop_Release(m_Path);
	f_prop_Release(m_文件类型);
	f_prop_Release(m_瓦片);
	f_prop_Release(m_预缩放);
	f_prop_Release(m_平滑法线);
	f_prop_Release(m_应用变换);
}

bool C_外部加载物体节点::f_update() {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	
	auto path = f_prop_Path(m_Path);
	if (path != m_上一次加载路径 || m_重写加载) {
		f_node_物体从主场景中移除(objs);
		f_node_从全局容器移除物体(objs);
		m_ObPtr.clear();

		m_上一次加载路径 = path.generic_string();


		auto 扩展名 = path.extension();
		if (f_prop_Bool(m_是否递归目录)) {
			f_递归加载物体(m_上一次加载路径);
		}
		else {
			f_加载物体(m_上一次加载路径);
		}


		uint32 num = m_ObPtr.size();
		f_core_array_resize((S_Array*)objs, num);

		for (uint32 i = 0; i < num; ++i) {
			auto& ob = m_ObPtr[i];

			

			if (ob->m_Type == E_物体类型::t_多边形) {
				f_node_构建多边形网格对象(ob, m_Ctx);
				f_node_物体绘制属性设置(ob);
				f_node_物体添加到全局容器(ob);


				S_多边形* 多边形 = f_ob_from多边形(ob);
				auto* 面 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_面);
				auto* 边 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_边);
				auto* 点 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_点);
				f_surface_多边形转网格(多边形, 面, 点, 边);


				f_surface_材质面区间(面, f_NodeCtx_get基本光照面材质());
				f_me_alloc多维材质槽(f_ob_getMesh(ob, E_物体网格元素类型::e_MT_轮廓边), 1, f_NodeCtx_get物理光照轮廓材质());
			}
			else {
				
			}
			

			auto* 面 = f_ob_getMesh(ob, E_物体网格元素类型::e_MT_面);
			
			if (f_prop_Bool(m_平滑法线)) {
				f_surface_计算面平滑法线(面);
			}

			if (f_prop_Bool(m_应用变换)) {
				auto mat = f_mat44_构建旋转缩放矩阵(ob->m_变换);
				f_surface_应用变换(面, mat);

				ob->m_变换.rotation = {};
				ob->m_变换.scale = {1,1,1};
			}

			f_mesh_计算包围盒(面);

			f_ob_setName(ob, f_file_get无后缀文件名(path.generic_u16string()));
			objs->ptr_userData[i] = ob;
		}


		num = DEF_Min(m_变换组.size(), num);
		f_get输出插座(1)->m_有新数据 = true;
		for (uint32 i = 0; i < num; ++i) {
			objs->ptr_userData[i]->m_变换 = m_变换组[i];
		}
		m_变换组.clear();

		m_重写加载 = false;
	}

	if (m_显示数据) {
		f_node_物体添加到主场景(objs);
		f_node_物体添加到全局容器(objs);
	}
	else {
		f_node_物体从主场景中移除(objs);
	}
	return false;
}

static std::mutex g_物体添加锁;
void C_外部加载物体节点::f_递归加载物体(std::string path) {
	S_目录文件包 dir;
	f_file_get目录下所有文件名(path, dir, ".obj");
	
	uint32 num = dir.目录.size();
//#pragma omp parallel for
	for(int32 i=0; i<num; ++i){
		f_递归加载物体(path + "/" + f_str_u16_to_u8(dir.目录[i]));
	}
	

	num = dir.文件.size();
//#pragma omp parallel for
	for (int32 i = 0; i < num; ++i) {
		f_加载物体(path + "/" + f_str_u16_to_u8(dir.文件[i]));
	}

}

void C_外部加载物体节点::f_加载物体(std::string path) {
	auto 文件扩展名 = f_file_get文件名后缀(path);
	auto 扩展名 = f_str_转小写(文件扩展名);


	std::vector<S_物体*> obs;
	std::vector<S_纹理添加列队> 纹理加载列队;

	if (扩展名 == ".fbx") {
		//f_ob_loadFBX(obs, m_上一次加载路径, f_prop_F32(m_预缩放), m_Ctx);

		uint32 num = obs.size();
		for (uint32 i = 0; i < num; ++i) {
			S_物体* 骨头物体 = f_递归构建骨骼网格体(obs[i], m_Ctx);
		}
	}
	else if (扩展名 == ".obj") {

		S_物体* ob = f_ob_创建(m_Ctx, E_物体类型::t_网格物体);
		//f_node_创建网格物体数据(m_Ctx, ob);

		//f_ob_loadOBJ(ob, m_上一次加载路径, m_Ctx, 纹理加载列队);
		obs.push_back(ob);
	}


	for (auto& e : obs) {
		g_物体添加锁.lock();
		m_ObPtr.emplace_back(e);
		g_物体添加锁.unlock();
	}
	
}

void C_外部加载物体节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_是否递归目录, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_是否序列, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_文件类型, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_Path, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_瓦片, 下一次读取数据指针);

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_12, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_预缩放, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_应用变换, 下一次读取数据指针);

			m_变换组.clear();
			下一次读取数据指针 = f_文件块_读序列数据块(下一次读取数据指针, m_变换组, false);
		}
	}
	free(文件块.m_data);
}

void C_外部加载物体节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_是否递归目录, 块);
	f_prop_Save(m_是否序列, 块);
	f_prop_Save(m_文件类型, 块);
	f_prop_Save(m_Path, 块);
	f_prop_Save(m_瓦片, 块);

	f_prop_Save(m_预缩放, 块);
	f_prop_Save(m_应用变换, 块);

	auto* obs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	m_变换组.clear();

	for (uint32 i = 0; i < obs->count; ++i) {
		m_变换组.push_back(obs->ptr_userData[i]->m_变换);
	}
	f_文件块_写序列数据块(块, m_变换组, false);

	f_file_保存文件块(f, 文件块, 块);
}

S_物体* C_外部加载物体节点::f_虚拟体() {
	auto& objs = *DEF_物体插座_1D数据(f_get输出插座(1), 0);
	if (objs.count) {
		return objs.ptr_userData[0];
	}
	return nullptr;
}

void C_外部加载物体节点::f_删除() {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_node_物体从主场景中移除(objs);
	f_node_从全局容器移除物体(objs);

}

void C_外部加载物体节点::f_回收() {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_node_物体添加到主场景(objs);
	f_node_物体添加到全局容器(objs);

}

void C_外部加载物体节点::f_Show(bool open) {
	auto* objs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_ob_set显示(objs, open);
}

C_节点基类 * f_node_创建外部加载物体节点(S_设备环境 & ctx, C_节点树 * 子节点树) {
	return new C_外部加载物体节点(ctx);
}

C_节点基类* f_node_加载外部加载物体节点(S_设备环境& ctx, FILE* f) {
	C_外部加载物体节点* node = new C_外部加载物体节点(ctx);
	return node;
}

void f_node_保存外部加载物体节点(C_节点基类* n, FILE* f) {
	C_外部加载物体节点* node = dynamic_cast<C_外部加载物体节点*>(n);
}







C_加载模型节点::C_加载模型节点(S_设备环境& ctx) : C_节点基类(DEF_加载模型节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"加载模型");
	m_Ctx = ctx;

	DEF_创建物体插座_I(u"物体");
	DEF_创建字符串插座_I(u"文件路径");
	DEF_创建物体插座_O(u"物体");

	m_文件类型 = f_alloc_EnumProp(nullptr, { {u"fbx", u""}, {u"obj", u""} }, u"文件类型", 0);
	m_文件类型.m_私有 = true;

	m_平滑法线 = f_alloc_BoolProp(nullptr, u"平滑法线");
	m_平滑法线.m_私有 = true;


	f_prop_enum(m_文件类型) = 1;
}

C_加载模型节点::~C_加载模型节点() {
	f_prop_Release(m_文件类型);
	f_prop_Release(m_平滑法线);
}

bool C_加载模型节点::f_update() {
	auto* ob = DEF_物体插座数据(f_get输入插座(1));
	auto& path = DEF_字符串插座数据(f_get输入插座(2));
	f_ob_load(ob, path, m_文件类型, m_平滑法线, m_Ctx);

	f_get输出插座(1)->f_setData(ob);
	return false;
}

std::string	C_加载模型节点::DEF_节点编译函数{
	m_ReleaseCode = "";
	m_Code = "";
	
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	//m_Code += DEF_S(f_file_补充路径后缀)"(" + socket2->f_getCode(0) + ", *(S_Props*)" + DEF_指针转字符串(&m_文件类型) + ");\n";
	m_Code += DEF_S(f_ob_load)"(" 
								+ socket1->f_getCode(0) 
								+ ", " + socket2->f_getCode(0) 
								+ ", *(S_Props*)" + DEF_指针转字符串(&m_文件类型)
								+ ", *(S_Props*)" + DEF_指针转字符串(&m_平滑法线)
								+ ", *(S_设备环境*)" + DEF_指针转字符串(&m_Ctx) 
								+ ");\n";
	

	f_get输出插座(1)->f_setCode(socket1->f_getCode(0)); 
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		return "";
	}
	return m_Code;
}

void C_加载模型节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_1, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_文件类型, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_加载模型节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_文件类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建加载模型节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_加载模型节点(ctx);
}

C_节点基类* f_node_加载加载模型节点(S_设备环境& ctx, FILE* f) {
	C_加载模型节点* node = new C_加载模型节点(ctx);
	return node;
}

void f_node_保存加载模型节点(C_节点基类* n, FILE* f) {
	C_加载模型节点* node = dynamic_cast<C_加载模型节点*>(n);
}




C_物体对称节点::C_物体对称节点(S_设备环境& ctx) : C_节点基类(DEF_物体对称节点) {
	f_setWName(u"物体对称");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建Vec3插座_v1_I(u"坐标");

	DEF_创建物体_1D插座_O(u"新物体");


	m_对称轴 = f_alloc_FlagBitsEnumProp(nullptr, *S_节点数据::g_对称轴枚举项, u"对称轴", 1);
	m_对称轴.m_私有 = true;


	m_对称复制的物体 = (S_OBArray*)f_core_array_new(0, sizeof(S_物体*));
	m_头次加载 = true;
}

C_物体对称节点::~C_物体对称节点() {
	f_prop_Release(m_对称轴);
	f_core_array_free((S_Array*)m_对称复制的物体);
}

bool C_物体对称节点::f_update() {
	auto* socket1 = f_get输入插座(1);

	auto* inData1 = DEF_物体插座_1D数据(f_get输入插座(1), 0);
	auto& coord = DEF_Vec3插座数据(f_get输入插座(2));

	auto* 新物体 = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	
	f_node_物体从主场景中移除(新物体);
	f_node_从全局容器移除物体(新物体);

	for (uint32 i = 0; i < 新物体->count; ++i) {
		f_node_OE_清除对称物体(新物体->ptr_userData[i]);
	}
	
	f_NE_对称物体(m_Ctx, inData1, 新物体, f_prop_UI32位域枚举(m_对称轴), coord);
	
	f_node_物体添加到主场景(新物体);
	f_node_物体添加到全局容器(新物体);

	if (m_对称复制的物体->count) {
		f_ob_复制物体属性(新物体, m_对称复制的物体);
		f_core_array_reserve((S_Array*)m_对称复制的物体, 0);
	}
	return false;
}

void C_物体对称节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
	
		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_1, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_对称轴, 下一次读取数据指针);
			下一次读取数据指针 = f_ob_递归加载物体(m_对称复制的物体, 下一次读取数据指针, m_Ctx);
		}
	}
	free(文件块.m_data);

	m_头次加载 = true;
}

void C_物体对称节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_对称轴, 块);
	auto* 新物体 = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	f_ob_递归保存物体(新物体, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建物体对称节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体对称节点(ctx);
}

C_节点基类* f_node_加载物体对称节点(S_设备环境& ctx, FILE* f) {
	C_物体对称节点* node = new C_物体对称节点(ctx);
	return node;
}

void f_node_保存物体对称节点(C_节点基类* n, FILE* f) {
	C_物体对称节点* node = dynamic_cast<C_物体对称节点*>(n);
}




C_取物体材质节点::C_取物体材质节点(S_设备环境& ctx) : C_节点基类(DEF_取物体材质节点) {
	f_setWName(u"取物体材质");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_Array1D插座_I(u"物体");
	DEF_创建I8_1D插座_I(u"槽");

	DEF_创建材质_1D插座_O(u"材质");
}

C_取物体材质节点::~C_取物体材质节点() {
}

bool C_取物体材质节点::f_update() {
	auto& obs = *DEF_物体插座_Array1D数据(f_get输入插座(1), 0);
	auto* ms = DEF_材质插座_1D数据(f_get输出插座(1), 0);

	uint32 num = obs.size();
	if (!num) {
		f_core_array_clear((S_Array*)ms);
		return false;
	}

	if (num > 1) {
		f_core_array_resize((S_Array*)ms, num);
		auto obPtr = obs.data();
		auto mPtr = ms->ptr_userData;
		for (uint32 i = 0; i < num; ++i) {
			mPtr[i] = f_ob_getMesh(obPtr[i])->m_多维材质槽[0].m_Material;
		}
	}
	else {
		f_core_array_resize((S_Array*)ms, 1);
		ms->ptr_userData[0] = f_ob_getMesh(obs[0])->m_多维材质槽[0].m_Material;
	}
	
	return false;
}

C_节点基类* f_node_创建取物体材质节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_物体对称节点(ctx);
}

C_节点基类* f_node_加载取物体材质节点(S_设备环境& ctx, FILE* f) {
	C_取物体材质节点* node = new C_取物体材质节点(ctx);
	return node;
}

void f_node_保存取物体材质节点(C_节点基类* n, FILE* f) {
	C_取物体材质节点* node = dynamic_cast<C_取物体材质节点*>(n);
}




//C_取物体光追材质节点::C_取物体光追材质节点(S_设备环境& ctx) : C_节点基类(DEF_取物体光追材质节点) {
//	f_setWName(u"取光追材质");
//	m_Ctx = ctx;
//
//	C_插座基类* socket;
//	DEF_创建物体_Array1D插座_I(u"物体");
//	DEF_创建I8_1D插座_I(u"槽");
//
//	DEF_创建板载缓存_1D插座_O(u"材质");
//}
//
//C_取物体光追材质节点::~C_取物体光追材质节点() {
//
//}
//
//bool C_取物体光追材质节点::f_update() {
//	auto& obs = *DEF_物体插座_Array1D数据(f_get输入插座(1), 0);
//	auto& ms = *DEF_板载缓存插座_1D数据(f_get输出插座(1), 0);
//
//	uint32 num = obs.size();
//	if (!num) {
//		ms.clear();
//		return false;
//	}
//
//	if (num > 1) {
//		ms.resize(num);
//		auto obPtr = obs.data();
//		auto mPtr = ms.data();
//		for (uint32 i = 0; i < num; ++i) {
//			auto& 链接材质 = f_ob_fromMesh(obs[0])->m_光追材质链接;
//			for (auto& e : 链接材质) ms.emplace_back(e);
//		}
//	}
//	else {
//		ms.resize(num);
//		auto& 链接材质 = f_ob_fromMesh(obs[0])->m_光追材质链接;
//		ms.assign(链接材质.begin(), 链接材质.end());
//	}
//
//	return false;
//}
//
//C_节点基类* f_node_加载取物体光追材质节点(S_设备环境& ctx, FILE* f) {
//	C_取物体光追材质节点* node = new C_取物体光追材质节点(ctx);
//	return node;
//}
//
//void f_node_保存取物体光追材质节点(C_节点基类* n, FILE* f) {
//	C_取物体光追材质节点* node = dynamic_cast<C_取物体光追材质节点*>(n);
//}




C_选择物体节点::C_选择物体节点(S_设备环境 & ctx) : C_节点基类(DEF_选择物体节点){
	f_setWName(u"选择物体");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_O(u"物体");

	m_物体列表 = f_alloc_PropArrayContainer((S_Array*)(f_get输出插座(1)->f_getData(0)), u"物体列表", E_值类型::e_Type_Object_1D);
	m_物体列表.m_私有 = true;
}

C_选择物体节点::~C_选择物体节点() {
	f_prop_Release(m_物体列表);
}

bool C_选择物体节点::f_update() {
	auto* obs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	
	if (m_物体名称.size()) {
		f_core_array_clear((S_Array*)obs);

		for (auto& e : m_物体名称) {
			auto* ob = f_node_从全局物体容器查找物体(e);
			if (ob) {
				f_core_array_push_back((S_Array*)obs, (uint8*)&ob);
			}
		}

		if (obs->count == m_物体名称.size()) {
			m_物体名称.clear();
		}
	}
	
	
	for (uint32 i = 0; i < obs->count; ++i) {
		m_物体名称.push_back(obs->ptr_userData[i]->m_Name);

		if (m_显示数据) {
			obs->ptr_userData[i]->m_显示 = true;
		}
		else {
			obs->ptr_userData[i]->m_显示 = false;
		}
	}

	return false;
}

void C_选择物体节点::f_Show(bool open) {
	auto* obs = DEF_物体插座_1D数据(f_get输出插座(1), 0);
	for (uint32 i = 0; i < obs->count; ++i) {
		obs->ptr_userData[i]->m_显示 = open;
	}
}

void C_选择物体节点::f_读取(FILE * f) {
	C_节点基类::f_读取(f);

	m_物体名称.clear();
	uint32 num = 0;
	fread(&(num), sizeof(uint32), 1, f);
	for (uint32 i = 0; i < num; ++i) {
		m_物体名称.push_back(f_file_读取字符串(f));
	}
}

void C_选择物体节点::f_写入(FILE * f) {
	C_节点基类::f_写入(f);
	
	S_OBArray* 拾取的物体 = (S_OBArray*)f_prop_ArrayContainer(m_物体列表);
	fwrite(&(拾取的物体->count), sizeof(uint32), 1, f);
	for (uint32 i = 0; i < 拾取的物体->count; ++i) {
		f_file_保存字符串(f, 拾取的物体->ptr_userData[i]->m_Name);
	}
}

C_节点基类* f_node_创建选择物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_选择物体节点(ctx);
}

C_节点基类* f_node_加载选择物体节点(S_设备环境& ctx, FILE* f) {
	C_选择物体节点* node = new C_选择物体节点(ctx);
	return node;
}
void		f_node_保存选择物体节点(C_节点基类* n, FILE* f) {
	C_选择物体节点* node = dynamic_cast<C_选择物体节点*>(n);
}




C_多边形物体节点::C_多边形物体节点(S_设备环境& ctx) : C_节点基类(DEF_多边形物体节点, E_节点类型::e_节点Type_物体) {
	
}

C_多边形物体节点::~C_多边形物体节点() {
	
}

bool C_多边形物体节点::f_update() {
	
	return false;
}

C_节点基类* f_node_创建多边形物体节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_多边形物体节点(ctx);
}

C_节点基类* f_node_加载多边形物体节点(S_设备环境& ctx, FILE* f) {
	C_多边形物体节点* node = new C_多边形物体节点(ctx);
	return node;
}

void        f_node_保存多边形物体节点(C_节点基类* n, FILE* f) {
	C_多边形物体节点* node = dynamic_cast<C_多边形物体节点*>(n);
}




C_目标摄像机节点::C_目标摄像机节点(S_设备环境& ctx) : C_节点基类(DEF_目标摄像机节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"摄像机");
	m_Ctx = ctx;
	m_更新方式 = E_节点更新方式::e_节点更新_逐帧;

	m_Ob = f_node_创建虚拟体(ctx);
	m_Ob->m_Name = u"摄像机虚拟体";

	m_目标 = f_node_创建虚拟体(ctx);
	m_目标->m_Name = u"摄像机目标虚拟体";
	m_目标->f_set缩放({0.2,0.2,0.2});

	m_摄像机 = (S_摄像机*)f_ob_创建(m_Ctx, E_物体类型::t_摄像机);
	m_摄像机->m_Name = u"摄像机";
	f_ob_add子物体(m_Ob, m_摄像机);


	m_Ob->m_颜色 = { 2,2,2,255 };
	m_目标->m_颜色 = {100,255,100,255};

	f_ob_set数据槽数量(m_Ob, 1);
	f_ob_set数据(m_Ob, f_surface_创建实例(S_节点数据::g_me_摄像机锥形, true, true, true, false, true, true), 0);
	f_ob_set材质(m_Ob, f_NodeCtx_get基本光照线段材质(), 0);
	

	f_ob_set数据槽数量(m_目标, 2);
	f_ob_set数据(m_目标, f_surface_创建实例(S_节点数据::g_me_立方体, true, true, true, false, true, true), 0);
	f_ob_set数据(m_目标, f_surface_创建实例(S_节点数据::g_me_链接线, true, true, true, false, true, true),1);
	f_ob_set材质(m_目标, f_NodeCtx_get基本光照线段材质(), 0);
	f_ob_set材质(m_目标, f_NodeCtx_get基本光照线段材质(), 1);
	f_ob_set附属类型(m_Ob, E_物体类型::t_摄像机);

	
	f_ob_set颜色2(m_Ob, m_Ob->m_颜色, m_Ob->m_实例ID, 0);
	f_ob_set颜色2(m_目标, m_目标->m_颜色, m_Ob->m_实例ID, 0);
	f_ob_set颜色2(m_目标, m_目标->m_颜色, m_Ob->m_实例ID, 1);

	
	f_ob_getMesh(m_Ob, 0)->m_Color = S_节点UI主题::uic_摄像机虚拟体;
	f_ob_getMesh(m_目标, 0)->m_Color = S_节点UI主题::uic_摄像机虚拟体;


	f_mesh_set绘制内存属性(f_ob_getMesh(m_Ob, 0), {});
	f_mesh_set绘制内存属性(f_ob_getMesh(m_目标, 0), {});
	f_mesh_set绘制内存属性(f_ob_getMesh(m_目标, 1), {});


	f_mesh_计算包围盒(f_ob_getMesh(m_Ob, 0));
	f_mesh_计算包围盒(f_ob_getMesh(m_目标, 0));

	f_ob_set线宽(m_Ob, 2.0, 0);
	f_ob_set线宽(m_目标, 2.0, 0);


	m_Ob->m_视口显示模式 = 1 | 2;
	m_Ob->m_视口显示模式 |= m_Ob->m_视口显示模式 << 16;
	m_目标->m_视口显示模式 = 1 | 2;
	m_目标->m_视口显示模式 |= m_目标->m_视口显示模式 << 16;



	f_node_物体添加到全局容器(m_Ob);
	f_node_物体添加到全局容器(m_目标);

	f_NodeCtx_录物体类节点(this);
	f_NodeCtx_录物体类节点(this, m_目标);
	f_NodeCtx_录物体类节点(this, m_摄像机);


	f_node_物体添加到主场景(m_Ob);
	f_node_物体添加到主场景(m_目标);
	


	C_插座基类* socket;
	DEF_创建物体插座_I(u"目标");
	DEF_创建F32插座_I(u"视野角度", &m_摄像机->m_视角);
	

	DEF_创建物体插座_O(u"摄像机");
	DEF_创建物体插座_O(u"目标");

	f_get输入插座(1)->f_setData(m_目标);
	f_get输出插座(1)->f_setData(m_Ob);
	f_get输出插座(2)->f_setData(m_目标);

	m_Ob->f_set位置({1,1,1});


	f_node_节点约束入栈(this);
	m_自定义更新方式 = true;
}

C_目标摄像机节点::~C_目标摄像机节点() {
}

bool C_目标摄像机节点::f_update() {
	f_异步解算();
	return false;
}

void C_目标摄像机节点::f_异步解算() {
	auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto* 相机物体 = DEF_物体插座数据(f_get输出插座(1), 0);

	目标物体->f_set旋转({});


	float32 视野角度 = DEF_F32插座数据(f_get输入插座(2));

	vec3 目标位置 = f_ob_get全局坐标(目标物体, 目标物体->m_实例ID);
	vec3 相机位置 = f_ob_get全局坐标(相机物体, 相机物体->m_实例ID);
	vec3 方向 = 相机位置 - 目标位置;

	vec2 比例 = { float32(m_摄像机->m_分辨率.x), float32(m_摄像机->m_分辨率.y) };
	m_摄像机->f_set宽高比(比例);
	m_摄像机->f_set视角(视野角度);

	m_摄像机->m_视距 = -vec_normalize(&方向);
	m_摄像机->m_视点 = (目标位置);
	m_摄像机->f_set视点偏移({});


	float32 z = m_摄像机->f_get旋转().z;

	vec4 quatX = f_graph_quat两向量(vec_normalize({ 方向.x, 0, 方向.z }), 方向);
	vec4 quatY = f_graph_quat两向量({ 0, 0, -DEF_ForwardDir }, vec_normalize({ 方向.x, 0, 方向.z }));
	vec4 Z轴四元数 = f_graph_从轴向角度计算四元数(方向, M_角度转弧度(z));

	vec4 quat = f_graph_quat相乘(quatX, quatY);
	quat = f_graph_quat相乘(Z轴四元数, quat);
	vec3 旋转 = f_graph_四元数转欧拉角(quat);
	相机物体->f_set旋转(旋转);
	

	if (旋转.x < 0) {
		旋转.y = sign(旋转.y) * 180 - 旋转.y;
	}
	旋转.x = M_弧度转角度(f_graph_两向量夹角弧度(vec_normalize({ 方向.x, 0, 方向.z }), 方向));
	旋转.y *= sign(方向.y);
	
	if (方向.y < 0) {
		旋转.x = -旋转.x;
		旋转.y += 180;
	}
	旋转.x = -旋转.x;
	旋转.z = z;
	
	m_摄像机->f_set旋转({ 旋转.x, -旋转.y + 180, 旋转.z });

	f_node_虚拟体_设置摄像机虚拟网格(相机物体, 目标物体, m_摄像机, 方向 * -m_摄像机->m_视距);
	
}

S_物体* C_目标摄像机节点::f_虚拟体() {
	return m_Ob;
}

void C_目标摄像机节点::f_删除() {
	f_node_从全局容器移除物体(m_Ob);
	f_node_从全局容器移除物体(m_目标);
}

void C_目标摄像机节点::f_回收() {
	auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto* 相机物体 = DEF_物体插座数据(f_get输出插座(1), 0);

	vec3 目标位置 = f_ob_get全局坐标(目标物体, 目标物体->m_实例ID);
	vec3 相机位置 = f_ob_get全局坐标(相机物体, 相机物体->m_实例ID);

	vec3 方向 = 相机位置 - 目标位置;
	f_node_设置摄像机虚拟网格(相机物体, m_摄像机);
	f_node_设置链接线方体虚拟网格(目标物体, { 0.1f, 0.1f, 0.1f }, 方向);

}

void C_目标摄像机节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//下一次读取数据指针 = f_prop_Load(m_是否改变原数据, 下一次读取数据指针);
		auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
		auto* 相机物体 = DEF_物体插座数据(f_get输出插座(1), 0);
		//下一次读取数据指针 = f_ob_Load物体(目标物体, 下一次读取数据指针);
		//下一次读取数据指针 = f_ob_Load物体(相机物体, 下一次读取数据指针);
	}

	free(文件块.m_data);

}

void C_目标摄像机节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_prop_Save(m_是否改变原数据, 块);

	auto* 目标物体 = DEF_物体插座数据(f_get输入插座(1), 0);
	auto* 相机物体 = DEF_物体插座数据(f_get输出插座(1), 0);
	//f_ob_Save物体(目标物体, 块);
	//f_ob_Save物体(相机物体, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建目标摄像机节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_目标摄像机节点(ctx);
}
C_节点基类* f_node_加载目标摄像机节点(S_设备环境& ctx, FILE* f) {
	C_目标摄像机节点* node = new C_目标摄像机节点(ctx);
	return node;
}
void f_node_保存目标摄像机节点(C_节点基类* n, FILE* f) {
	C_目标摄像机节点* node = dynamic_cast<C_目标摄像机节点*>(n);
}





C_设置物体中心节点::C_设置物体中心节点(S_设备环境& ctx) : C_节点基类(DEF_设置物体中心节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"设置物体中心");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建Vec3_1D插座_I(u"中心");
	DEF_创建物体_1D插座_O(u"物体");


	m_中心方式 = f_alloc_EnumProp(nullptr, {
		{u"自定义输入", u""},
		{u"到几何中心", u""},
		{u"到世界中心", u""},
	}, u"中心调整方式");
	m_中心方式.m_私有 = true;

	m_中心位置 = f_alloc_EnumProp(nullptr, {
		{u"保持", u""},
		{u"归零", u""},
		{u"到世界中心", u""},
							  }, u"位置调整方式");
	m_中心位置.m_私有 = true;

	m_复制物体 = f_alloc_BoolProp(nullptr, u"复制物体");
	m_复制物体.m_私有 = true;

}

C_设置物体中心节点::~C_设置物体中心节点() {
	f_prop_Release(m_中心方式);
	f_prop_Release(m_中心位置);
	f_prop_Release(m_复制物体);
}

bool C_设置物体中心节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	if (socket1->f_get是否有输入新数据() == false) {
		return false;
	}

	auto* obs = DEF_物体插座_1D数据(socket1);

	if (socket1->f_isLink()) {
	#pragma omp parallel for
		for (int32 i = 0; i < obs->count; ++i) {
			switch (obs->ptr_userData[i]->m_Type) {
				case E_物体类型::t_多边形: {
					//break;
				}
				case E_物体类型::t_网格物体: {
					S_Mesh* me = f_ob_getMesh(obs->ptr_userData[i], E_物体网格元素类型::e_MT_面);
					f_mesh_计算包围盒(me);

					vec3 中心 = me->m_包围盒->pos;

					switch (*me->m_顶点配置Flags) {
						case E_顶点组合标志::e_坐标_法线_UV: {
							S_VNT1* vert = f_buf_VNT_ptr(*me->m_顶点);

							uint32 vNum = me->m_顶点->m_Mem.m_数量;
							for (uint32 顶点id = 0; 顶点id < vNum; ++顶点id) {
								vert[顶点id].vert -= 中心;
							}
							break;
						}
						default:
							break;
					}
				
					me->m_Bound->min -= 中心;
					me->m_Bound->max -= 中心;

					me->m_包围盒->pos = me->m_Bound->min + me->m_包围盒->size * 0.5;
					obs->ptr_userData[i]->f_set位置(中心);
					break;
				}
			
				default:
					break;
			}
		}

		f_get输出插座(1)->f_setData(obs);
	}
	else {
		f_get输出插座(1)->f_setData((void*)nullptr);
	}


	
	return false;
}

void C_设置物体中心节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_8, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_中心方式, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_中心位置, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_复制物体, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_设置物体中心节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_中心方式, 块);
	f_prop_Save(m_中心位置, 块);
	f_prop_Save(m_复制物体, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建设置物体质心节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体中心节点(ctx);
}
C_节点基类* f_node_加载设置物体质心节点(S_设备环境& ctx, FILE* f) {
	C_设置物体中心节点* node = new C_设置物体中心节点(ctx);
	return node;
}
void f_node_保存设置物体质心节点(C_节点基类* n, FILE* f) {
	C_设置物体中心节点* node = dynamic_cast<C_设置物体中心节点*>(n);
}




C_设置物体法线节点::C_设置物体法线节点(S_设备环境& ctx) : C_节点基类(DEF_设置物体法线节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"设置物体法线");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建Vec3_1D插座_I(u"法线");
	DEF_创建物体_1D插座_O(u"物体");


	m_法线类型 = f_alloc_EnumProp(nullptr, {
		{u"自定义输入", u""},
		{u"自动平滑", u""},
		{u"中心", u""},
							  }, u"法线类型");
	m_法线类型.m_私有 = true;

	m_复制物体 = f_alloc_BoolProp(nullptr, u"复制物体");
	m_复制物体.m_私有 = true;
}

C_设置物体法线节点::~C_设置物体法线节点() {
	f_prop_Release(m_法线类型);
	f_prop_Release(m_复制物体);
}

bool C_设置物体法线节点::f_update() {
	auto* socket1 = f_get输入插座(1);

	if (socket1->f_get是否有输入新数据() == false) {
		return false;
	}


	auto* obs = DEF_物体插座_1D数据(socket1);

	if (socket1->f_isLink()) {
	#pragma omp parallel for
		for (int32 i = 0; i < obs->count; ++i) {
			switch (obs->ptr_userData[i]->m_Type) {
				case E_物体类型::t_多边形: {
					//break;
				}
				case E_物体类型::t_网格物体: {
					S_Mesh* me = f_ob_getMesh(obs->ptr_userData[i], E_物体网格元素类型::e_MT_面);

					f_surface_计算面平滑法线(me);

					break;
				}

				default:
					break;
			}
			obs->ptr_userData[i]->m_isUpdate = true;
		}
		
		f_get输出插座(1)->f_setData(obs);
	}
	else {
		f_get输出插座(1)->f_setData((void*)nullptr);
	}

	return false;
}

void C_设置物体法线节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_8, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_法线类型, 下一次读取数据指针);
			下一次读取数据指针 = f_prop_Load(m_复制物体, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_设置物体法线节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_法线类型, 块);
	f_prop_Save(m_复制物体, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建设置物体法线节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体法线节点(ctx);
}
C_节点基类* f_node_加载设置物体法线节点(S_设备环境& ctx, FILE* f) {
	C_设置物体法线节点* node = new C_设置物体法线节点(ctx);
	return node;
}
void f_node_保存设置物体法线节点(C_节点基类* n, FILE* f) {
	C_设置物体法线节点* node = dynamic_cast<C_设置物体法线节点*>(n);
}





C_设置物体绘制模式节点::C_设置物体绘制模式节点(S_设备环境& ctx) : C_节点基类(DEF_设置物体绘制模式节点, E_节点类型::e_节点Type_物体) {
	f_setWName(u"设置物体绘制模式");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建物体_1D插座_I(u"物体");
	DEF_创建UI32_1D插座_I(u"类型");
	DEF_创建物体_1D插座_O(u"物体");


	m_绘制类型 = f_alloc_FlagBitsEnumProp(&S_节点数据::g_物体全局显示模式,
										*S_节点数据::g_物体显示模式项_光追, 
										u"显示模式", S_节点数据::g_物体全局显示模式);
	m_绘制类型.m_私有 = true;
	f_prop_UI32位域枚举(m_绘制类型) = 0;
}

C_设置物体绘制模式节点::~C_设置物体绘制模式节点() {
	f_prop_Release(m_绘制类型);
}

bool C_设置物体绘制模式节点::f_update() {
	auto* socket2 = f_get输入插座(2);

	auto* ob = DEF_物体插座_1D数据(f_get输入插座(1));
	

	if (socket2->f_isLink()) {
		auto* fb = DEF_UI32插座_1D数据(f_get输入插座(1));

		bool 多例1 = fb->count >= ob->count;
		for (uint32 i = 0; i < ob->count; ++i) {
			ob->ptr_userData[i]->m_视口显示模式 = 多例1 ? fb->ptr_userData[i] : fb->ptr_userData[0];
		}
	}
	else {
		uint32 fb = f_prop_UI32位域枚举(m_绘制类型);

		for (uint32 i = 0; i < ob->count; ++i) {
			ob->ptr_userData[i]->m_视口显示模式 = fb;
		}
	}

	f_get输出插座(1)->f_setData(ob, 0);
	return false;
}

void C_设置物体绘制模式节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_8, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_绘制类型, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_设置物体绘制模式节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_绘制类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建设置物体绘制模式节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置物体法线节点(ctx);
}

C_节点基类* f_node_加载设置物体绘制模式节点(S_设备环境& ctx, FILE* f) {
	C_设置物体法线节点* node = new C_设置物体法线节点(ctx);
	return node;
}

void f_node_保存设置物体绘制模式节点(C_节点基类* n, FILE* f) {
	C_设置物体法线节点* node = dynamic_cast<C_设置物体法线节点*>(n);
}








//if (f_prop_Bool(S_节点数据状态::g_打开编辑模式)) {
		//	f_NE_骨骼编辑状态颜色设置({ m_骨骼对象 });
		//}
		//else {
		//	f_NE_骨骼物体状态颜色设置({ m_骨骼对象 });
		//}








